Solaris Naming Administration Guide

Chapter 20 FNS Quickstart

This chapter provides a summary overview of FNS, a brief description of setup and configuration steps, and a programming example. Experienced administrators may find that this quick start chapter is all that they need.

For more detailed information, see the remaining chapters of this part. For more detailed initial FNS setup and configuration information, see Solaris Naming Setup and Configuration Guide.

Federated Naming Service (FNS)

Federated Naming Service (FNS) provides a method for federating multiple naming services under a single, simple interface for naming and directory operations. Naming services that can be linked with FNS include: NIS+, NIS, files, DNS, and X.500/LDAP.

X/Open Federated Naming (XFN)

The programming interface and policies that FNS supports are specified by XFN (X/Open Federated Naming).

Why FNS?

FNS is useful for the following reasons:

Composite Names and Contexts

Fundamental to FNS are the notions of composite names and contexts.

Composite Names

A composite name is a name that spans multiple naming systems.

A composite name consists of an ordered list of components. Each component is a name from the namespace of a single naming system. Individual naming systems are responsible for the syntax of each component. FNS defines the syntax for constructing a composite name using names from component naming systems. Composite names are composed left to right using the slash character (/) as the component separator.

For example, the composite name .../doc.com/site/bldg-5.alameda consists of four components: ..., doc.com, site, and bldg-5.alameda.

Contexts

A context provides operations for:

A context contains a set of name-to-reference bindings. Each reference contains a list of communication end-points or addresses. The federated naming system is formed by contexts from one naming system being bound in the contexts of another naming system. Resolution of a composite name proceeds from contexts within one naming system to those in the next until the name is resolved.

Attributes

Attributes may be applied to named objects. Attributes are optional. A named object can have no attributes, one attribute, or multiple attributes.

Each attribute has a unique attribute identifier, an attribute syntax, and a set of zero or more distinct attribute values.

XFN defines the base attribute interface for examining and modifying the values of attributes associated with existing named objects. These objects can be contexts or any other types of objects. Associated with a context are syntax attributes that describe how the context parses compound names.

The extended attribute interface contains operations that search for specific attributes and that create objects and their associated attributes.

Enterprise Naming Services

Enterprise-level naming services are used to name objects within an enterprise. FNS currently supports three enterprise-level naming services:

NIS+

NIS+ is the preferred enterprise-wide information service in the Solaris operating environment environment. FNS organization units correspond to NIS+ domains and subdomains. There is one orgunit context for each domain and subdomain.

Under NIS+, FNS context and attribute data are stored in NIS+ tables. These tables are stored in NIS+ directory objects named ctx_dir. There is a ctx_dir directory object for each NIS+ domain and subdomain, residing at the same level as the domain's groups_dir and org_dir directory objects. Thus, the directory object ctx_dir.sales.doc.com. contains FNS tables which store FNS context and attribute data for the sales.doc.com. domain.

Under NIS+, you use FNS and NIS+ commands to work with the information in FNS tables. Do not edit these tables directly or manipulate them with UNIX commands.

NIS

NIS is an enterprise-wide information service in the Solaris environment. Each enterprise is a single NIS domain. There is one FNS organizational unit which corresponds to the single NIS domain.

Under NIS, FNS context and attribute data are stored in NIS maps. These maps are stored in a /var/yp/domainname directory on a NIS server. Under NIS, the super user can use FNS commands to work with the information in FNS maps.

NIS Clients Can Update Contexts With FNS if SKI is Running

If certain conditions are met, any NIS client (machine, process, or user) can use FNS commands such as fncreate_fs or fncreate_printer to update the client's own contexts. This allows NIS clients to use FNS commands to update applications such as Printer Administrator, CDE Calendar Manager, Admin Tool and others.

For non-super-users to update their own contexts with FNS commands, the following conditions must be met:


Note -

SKI does not support 64-bit mode. Thus, NIS clients cannot update contexts in 64-bit mode.


Files-Based

Files refers to the naming files normally found in a machine's /etc directory. These machine-based files contain UNIX user and password information, host information, mail aliases, and so forth. They also support Solaris-specific data such as the automount maps.

Under a files-based naming system, FNS context and attribute data is stored in files. These FNS files are stored in machine's /var/fn directory. (The /var/fn directory does not have to be on each machine, it could be exported from an NFS file server.)

Under a files naming system, you use FNS commands to work with the information in FNS files.

Global Naming Services

FNS also supports federating NIS+ and NIS with DNS and X.500. This means that you can connect enterprise level namespaces with global namespaces to make the enterprise objects accessible in the global scope.

FNS currently supports the following global naming services:

FNS Naming Policies

FNS defines naming policies so that users and applications can depend on and use the shared namespace.

Within an enterprise, there are namespaces for organizational units, sites, hosts, users, files and services, referred to by the names orgunit, site, host, user, fs (for file system), and service. These namespaces can also be named by preceding each name with an underscore (_). For example, host and _host are considered identical.

Table 20-1 summarizes the FNS policies for enterprise-level namespaces.

Table 20-1 FNS Policy Summary

Context Type 

Subordinate Contexts 

Parent Contexts 

orgunit _orgunit

site user host fs service

enterprise root 

site _site

user host fs service

enterprise root 

orgunit

user _user

service fs

enterprise root 

orgunit

host _host

service fs

enterprise root 

orgunit

service _service

Printer and other applications 

enterprise root 

orgunit site user host

fs _fs(file system)

(none) 

enterprise rootorgunit site user host

Organization Names

The binding of an FNS orgunit is determined by the underlying naming service:

The types of objects that may be named relative to an organizational unit name are: user, host, service, fs, and site. For example:

Site Names

Site names are created as needed. The types of objects that may be named relative to a site name are: user, host, service and fs. For example:

User Names

User names correspond to names in the corresponding passwd table in NIS+, the passwd map in NIS, or the /etc/passwd file under files. A user's file context is obtained from his or her passwd entry.

The types of objects that may be named relative to a user name are: service, and fs. For example:

Host Names

Host names correspond to names in the corresponding hosts table in NIS+, the hosts map in NIS, or the /etc/hosts file under files. The host's file context corresponds to the files systems exported by the host.

The types of objects that may be named relative to a host name are: service, and fs. For example:

Service Names

Service names correspond to, and are determined by, service applications. The service context must be named relative to an organization, user, host, or site context. For example:

File Names

File system names correspond to file names. For example:

Getting Started

To begin using FNS with your underlying name service, you run the fncreate command.

The fncreate command recognizes the underlying naming service in which FNS contexts are to be created (such as, NIS+, NIS, or files). To specify a specific naming service, you must run the fnselect command as explained in "Designating a Non-Default Naming Service"..

Designating a Non-Default Naming Service

By default:

You can also explicitly specify a non-default target naming service by using the fnselect command. For example the following command selects the target naming service to be NIS.


# fnselect nis

Creating the FNS Namespace

Once the naming service has been selected either using the default policy or explicitly via fnselect, you can execute the following command to create the FNS namespace:


# fncreate -t org org//

This creates all the necessary contexts for users and hosts in the corresponding naming service.

NIS+ Considerations

When your primary enterprise-level naming service is NIS+, take into account the following points.

NIS+ Domains and Subdomains

The command syntax shown above creates the FNS namespace for the root NIS+ domain. To specify a domain other than the root, add the domain name between the double slashes, as in:


# fncreate -t org org/sales.doc.com./

Note the trailing dot after the fully qualified sales.doc.com. domain name.

Space and Performance Considerations

The fncreate commands creates NIS+ tables and directories in the ctx_dir directory. The ctx_dir directory object resides at the same level as the NIS+ groups_dir and org_dir directory objects of the domain.

NIS+ Security Requirements

The user who runs fncreate and other FNS commands is expected to have the necessary NIS+ credentials.

The environment variable NIS_GROUP specifies the group owner for the NIS+ objects created by fncreate. In order to facilitate administration of the NIS+ objects, NIS_GROUP should be set to the name of the NIS+ group responsible for FNS administration for that domain prior to executing fncreate and other FNS commands.

Changes to NIS+ related properties, including default access control rights, could be effected using NIS+ administration tools and interfaces after the context has been created. The NIS+ object name that corresponds to an FNS composite name can be obtained using fnlookup and fnlist, described later in this document.

NIS Considerations

The fncreate command must be executed by superuser on the NIS system that will serve as the NIS master server for the FNS maps.

The NIS maps used by FNS are stored in /var/yp/domainname.

Any changes to the FNS information can only be done by the superuser on the FNS NIS master server using FNS commands.

Files Considerations

When using fncreate with the -t org option to create your FNS namespace, the command must be executed by superuser on the machine that owns the file system on which /var is located. The files used by FNS are stored in the /var/fn directory.

Once users' contexts are created, users are allowed to modify their own contexts based on their UNIX credentials.

If exported, the file system /var/fn can be mounted by other systems to access the FNS namespace.

Browsing the FNS Namespace

Once the namespace has been set up, you can browse using the following commands:

Listing Context Contents

The fnlist command displays the names and references bound in the context of name.


fnlist [-lvA] [name]
Table 20-2 fnlist Command Options

Option 

Description 

name

A composite name. Displays the names bound in the context of name

-v

Verbose. Displays the binding in more detail 

-l

Also displays the bindings of the names bound in the named context 

-A

Forces fnlist to obtain its information from the authoritative server. Under NIS and NIS+, that is the domain master server. The -A option has no effect when the primary naming service is files.

For example:

To list names in the initial context:


% fnlist

To list in detail all the users in the current organizational unit:


% fnlist -v user

To list the contents of the service context for the user pug:


% fnlist user/pug/service

To list names and bindings from the authoritative server:


% fnlist -l -A

Displaying the Bindings of a Composite Name

The fnlookup command shows the binding of the given composite name.


fnlookup [-vAL] [name]
Table 20-3 fnlookup Command Options

Option 

Description 

name

The name of a context. Displays the binding and XFN link of name

-v

Verbose. Displays the binding in more detail 

-L

Also displays the XFN link that the name is bound to 

-A

Forces fnlist to obtain its information from the authoritative server. Under NIS and NIS+, that is the domain master server. The -A option has no effect when the primary naming service is files-based.

For example: to display the binding of user/ana/service/printer:


# fnlookup user/ana/service/printer

Showing the Attributes of a Composite Name

The fnattr command displays (and updates) the attributes of the given composite name.

For example, to search for the attributes associated with a user named ada:


# fnattr user/ada

To search for the attributes associated with a printer named laser-9:


# fnattr thisorgunit/service/printer/laser-9

See "Working With Attributes" for more details.

Searching for FNS Information

The fnsearch command displays the names and, optionally, the attributes and references of objects bound at or below a composite name whose attributes satisfy the given search criteria.

For example:

To list the users and their attributes who have an attribute called realname:


% fnsearch user realname

To list the users with the attribute realname whose value is Ravi Chattha:


% fnsearch user "realname == 'Ravi Chattha'"

The fnsearch command uses the common Boolean operators. Note the use of double and single quotes and double equals sign in the above example.

Updating the Namespace

Once the namespace has been set up, you can add, delete, and modify elements using the following commands:

FNS Administration Privileges

FNS System administration varies according to the underlying naming service:

The ability of users to make changes to their own user sub-contexts varies according to the underlying naming service:

Binding a Reference to a Composite Name

The fnbind command is used to bind an existing reference (name) to a new composite name.


fnbind -r [-s][-v][-L] name [-O|-U] newname reftype addrtype [-c|-x] address
Table 20-4 fnbind Command Options

Option 

Description 

name

The existing composite name 

newname

The composite name of the new binding 

addrtype

Address type to use. Applications-specific such as onc_cal_str.

address

Address contents to use. For example, tsvi@altair.

reftype

Reference type to use. Applications-specific such as one_calendar.

-s

Bind to newname even if it is already bound. This replaces the previous binding of newname. Without -s, fnbind fails if newname is already bound.

-v

Display the reference that will be bound to newname.

-L

Create an XFN link using oldname and bind it to newname.

-r

Bind newname to the reference constructed by the command line arguments.

-c

Store address contents in the form as entered, do not use XDR-encoding.

-x

Convert address to a hexadecimal string without converting it to XDR-encoding.

-O

The identifier format is FN_ID_ISO_OID_STRING, an ASN.1 dot-separated integer list string. 

-U

The identifier format is FN_ID_DCE_UUID, a DCE UUID in string form. 

For example:

To add a calendar binding for the user jamal:


# fnbind -r user/jamal/service/calendar onc_calendar onc_cal_str
 jamal@cygnus

To replace the existing binding of org//service/Sparc-4 with that of org//service/printer:


# fnbind -s org//service/printer org//service/Sparc-4

To copy the reference site/bldg-5/service/printer to user/ando/service/printer:


# fnbind site/bldg-5/service/printer user/ando/service/printer

To bind the reference site/bldg-5/service/printer to user/ando/service/printer using a symbolic link:


# fnbind -L site/bldg-5/service/printer user/ando/service/printer

To bind the name thisens/service/calendar to the address staff@altair, when staff@altair is a reference of the type onc_cal and an address of the type onc_cal_str:


# fnbind -r thisens/service/calendar onc_calendar onc_cal_str staff@altair

To bind newname to the reference constructed by its command line address


# fnbind -r [-sv] newname [-O|-U] reftype {[-O|-U] addrtype [-c|-x] address}

Removing Bindings

The fnunbind name command is used to remove bindings.

For example: to remove the binding for user/jsmith/service/calendar:


# fnunbind user/jsmith/service/calendar

Creating New Contexts

The fncreate command is used to create contexts.


fncreate -t context [-f file] [-o] [-r reference] [-s] [-v] [-D] name
Table 20-5 fncreate Command Options

Option 

Description 

-t context

Create context of type context. Context types can be: org, hostname, host, username, user, service, fs, site, nsid, and generic.

-f file

Use an input file to list users and hosts for whom to create contexts. 

-r reference

Type of reference. The -r reference option can only be used with -t generic.

name

A composite name 

-o

Create only the context identified by name.

-s

Overwrite (supersede) any existing binding. If -s is not used, fncreate will fail if name is already bound.

-D

Display information about each context and corresponding tables, directories, and files as it is created. 

-v

Verbose. Display information about each context as it is displayed. 

For example:

To create a context and subcontexts for the root organization:


# fncreate -t org org//

To create a context, and subcontexts, for the host deneb:


# fncreate -t host host/deneb

To create a context, service and file subcontexts, and then add a calendar binding for the user sisulu:


# fncreate -t user user/sisulu
# fnbind -r user/sisulu onc_calendar onc_cal_str sisulu@deneb

To create a site context for the sales organization:


# fncreate -t site org/sales/site/

The site context supports a hierarchal namespace, with dot-separated right-to-left names, which allows sites to be partitioned by their geographical coverage relationships. For example, to create a site context alameda and a site subcontext bldg-6.alameda for it:


# fncreate -t site org/sales/site/alameda
# fncreate -t site org/sales/site/bldg-6.alameda

Creating File Contexts

Table 20-6 fncreate_fs Command Options

Option 

Description 

name

The name of the file context 

options

Mount options 

mount

Mount location 

-f file

Input file 

-v

Verbose. Displays information about the contexts being created 

-r

Replace the bindings in the context name with those specified in the input.

For example:

To create a file system context named data for the sales organization bound to the /export/data path of an NFS server named server4.


# fncreate_fs org/sales/fs/data server4:/export/data

To create a hierarchy of file system contexts for the sales organization named buyers and buyers/orders mounted on two different servers:


# fncreate_fs org/sales/fs/buyers server2:/export/buyers
# fncreate_fs org/sales/fs/buyers/orders server3:/export/orders

To create a file system context named leads for the sales organization bound to a server and path specified by an input file named input_a:


# fncreate_fs -f input_a org/sales/fs/leads

(See the fncreate_fs man page for information on input file format.)

Creating Printer Contexts

The fncreate_printer command creates printer contexts for organizations, users, hosts and site contexts. The printer context is created under the service context of the respective composite name.


fncreate_printer [-vs] name printer [prntaddr]

fncreate_printer [-vs] [-f [file]] name
Table 20-7 fncreate_printer Command Options

Option 

Description 

name

The name of the org, host, user, or site of the printer 

printer

The name of the printer 

prntaddr

The printer address in the form <addresstype>=<address>

-f file

Use the named file as input for a list of printers to be created. The input file is in the format of the /etc/printers.conf file. If neither a printer name nor a -f file is specified, fncreate_printer uses the /etc/printer.conf file on the machine where fncreate_printer is run as a default input file.

-s

Replace an existing address with the same address-type. 

-v

Verbose. Displays the binding in more detail 

For example:

To create printers for the sales organization based on the printers listed in the /etc/printers.conf file of the machine on which fncreate_printer is run:


# fncreate_printer -s org/sales/

Assume that the machine altair is the server for a printer named Sparc-5. To create a printer named invoices for the user nguyen that is actually the Sparc-5 printer:


# fncreate_printer user/nguyen invoices bsdaddr=altair,Sparc-5

It is also possible to organize printers hierarchically. For example, the fncreate_printer command can create printer contexts for the printers, color, color/inkjet and color/Sparc with the resulting contexts:


org/doc.com/service/printer/color
org/doc.com/service/printer/color/inkjet
org/doc.com/service/printer/color/Sparc

To create the above contexts, you would run:


# fncreate_printer org/doc.com color bsdaddr=colorful,color
# fncreate_printer org/doc.com color/inkjet bsdaddr=colorjet,inkjet
# fncreate_printer org/doc.com color/Sparc bsdaddr=colorprt,Sparc

Destroying Contexts

The fndestroy command is used to destroy empty contexts.

For example, to destroy the service context of the user patel:


# fndestroy user/patel/service

Working With Attributes

The fnattr command can be used to add, delete or modify attributes associated with a name. You can make modifications one at a time, or batch several within the same command.

Table 20-8 fnattr Command Options

Option 

Description 

name

The composite name 

attrib

The identifier of an attribute 

values

One or more attribute values 

oldvalue

An attribute value to be replaced by a new value 

newvalue

The attribute value that replaces an old value 

-a

Add an attribute 

-d

Destroy an attribute 

-l

List attributes 

-m

Modify an attribute 

-s

Replace all old attribute values with the new values for the attribute specified. 

-O

The identifier format is FN_ID_ISO_OID_STRING, an ASN.1 dot-separated integer list string. 

-U

The identifier format is FN_ID_DCE_UUID, a DCE UUID in string form. 

For example:

To show all of the attributes associated with the user name rosa:


# fnattr user/rosa

To display the size attribute associated with the user uri:


# fnattr user/uri/ size

For a user named devlin, to add an attribute named shoesize with a value of small, delete the hatsize attribute, and change the dresssize attribute value from 12 to 8:


# fnattr user/devlin -a shoesize small -d hatsize -m dresssize 12 8

Federating a Global Namespace

You can federate NIS+ or NIS to a global naming service like DNS and X.500.

To federate an NIS+ or NIS namespace under DNS or X.500, you first need to obtain the root reference for the NIS+ hierarchy or NIS domain.

From the point of view of the global name service, the root reference is known as the next naming system reference because it refers to the next naming system beneath the DNS domain or X.500 entry. To federate NIS+ or NIS with a global name service, you add the root reference information to that global service.

Once you have added the root reference information to the global service, clients outside of your NIS+ hierarchy or NIS domain can access and perform operations on the contexts in the NIS+ hierarchy or NIS domain. Foreign NIS+ clients access the hierarchy as unauthenticated NIS+ clients.

For example:

If NIS+ is federated underneath the DNS domain doc.com., you can now list the root of the NIS+ enterprise using the command


# fnlist .../doc.com/

If NIS+ is federated underneath the X.500 entry /c=us/o=doc, you can list the root of the NIS+ enterprise using the command:


# fnlist .../c=us/o=doc/

Note the mandatory trailing slash in both examples.

Copying and Converting FNS Contexts

The fncopy command can be used to copy or convert an FNS context and attributes to a new FNS context.

By using the -i and -o options, you can copy FNS contexts based on one underlying enterprise-level name service to a context based on a different underlying name service. For example, if you have an FNS installation running on top of NIS, and you upgrade your NIS service to NIS+, you can use fncopy to create a new context using NIS+.

Note that:

Table 20-9 fncopy Command Options

Option 

Description 

-i oldservice

The old (input) underlying enterprise-level name service. For example, -i nis specifies that the old service is NIS. Allowed values are files, nis, nisplus.

-o newservice

The new (output) underlying enterprise-level name. For example, o nisplus specifies that the new service is NIS+. Allowed values are files, nis, nisplus.

-f filename

A text file listing FNS contexts to be copied. In the absence of the -i and -o options, contexts must be identifies using global names.

oldcontext

The name of the context being copied 

newcontext

The name of the context being created or copied to. 

For example, to copy the doc.com printer contexts (and sub-contexts) and bindings to orgunit/east/doc.com:


# fncopy .../doc.com/service/printer .../doc.com/orgunit/east/service/printer

To copy the NIS FNS users' contexts specified in the file user_list to a NIS+ FNS users' context of the orgunit west/doc.com:


# fncopy -i nis -o nisplus -f /etc/user_list thisorgunit/user org/doc.com/user

Namespace Browser Programming Examples

The programming examples in this section shows the usage of XFN APIs to perform the following operations:

Listing Names Bound in a Context

The example below shows XFN operations to list a context.


#include <stdio.h>
#include <xfn/xfn.h>
#include <string.h>
#include <stdlib.h>
/*
 This routine returns the list of names
 bound under the given context (ctx_name).
 Examples of ctx_name are "user", "thisorgunit/service",
	host/alto/service, user/jsmit/service/calendar, etc.,
*/
typedef struct fns_listing {
	char *name;
	struct fns_listing *next;
} fns_listing;
fns_listing *
fns_list_names(const char *ctx_name)
{
	FN_status_t *status;
	FN_ctx_t *initial_context;
	FN_composite_name_t *context_name;
	FN_namelist_t *name_list;
	FN_string_t *name;
	unsigned int stat;
	fns_listing *head = 0, *current, *prev;
	int no_names = 0;
	status = fn_status_create();
	/* Obtain the initial context */
	initial_context = fn_ctx_handle_from_initial(0, status);
	if (!fn_status_is_success(status)) {
		fprintf(stderr, "Unable to obtain intial context\n");
		return (0);
	}
	context_name = fn_composite_name_from_str((unsigned char *)
                  ctx_name);
	/* FNS call to list names */
	name_list = fn_ctx_list_names(initial_context, context_name,
               status);
	if (!fn_status_is_success(status)) {
		fprintf(stderr, "Unable to list names\n");
		return (0);
	}
	/* Obtain the names individually */
	while (name = fn_namelist_next(name_list, status)) {
		no_names++;
		current = (fns_listing *) malloc(sizeof(fns_listing));
		current->name = (char *)
		 malloc(strlen((char *) fn_string_str(name, &stat)) + 1);
		strcpy(current->name, (char *) fn_string_str(name, &stat));
		current->next = 0;
		if (head) {
			prev->next = current;
			prev = current;
		} else {
			head = current;
			prev = current;
		}
		fn_string_destroy(name);
	}
	fn_namelist_destroy(name_list);
	fn_status_destroy(status);
	fn_ctx_destroy(initial_context);
	return (head);

Creating a Binding

Example 20-1 shows how to create a binding.


Example 20-1 Creating a Binding


#include <stdio.h>
#include <xfn/xfn.h>
#include <string.h>
/*
 This routine creates a binding with a name provided by "name"
 and having a reference type "reference_type" and address type
 "address_type".
 An example of using the function could be:
	 fns_create_bindings(
	 "user/jsmith/service/calendar",
	 "onc_calendar",
	 "onc_cal_str",
	 "jsmith&calserver");
*/
int fns_create_bindings(
 char *name,
 char *reference_type,
 char *address_type,
 char *data)
{
	int return_status;
	FN_composite_name_t *binding_name;
	FN_identifier_t ref_id, addr_id;
	FN_status_t *status;
	FN_ref_t *reference;
	FN_ref_addr_t *address;
	FN_ctx_t *initial_context;
	/* Obtain the initial context */
	status = fn_status_create();
	initial_context = fn_ctx_handle_from_initial(0, status);
	/* Check status for any error messages */
	if ((return_status = fn_status_code(status)) != FN_SUCCESS) {
		fprintf(stderr, "Unable to obtain the initial context\n");
		return (return_status);
	}
	/* Get the composite name for the printer name */
	binding_name = fn_composite_name_from_str((unsigned char *) name);
	/* Construct the Address */
	addr_id.format = FN_ID_STRING;
	addr_id.length = strlen(address_type);
	addr_id.contents = (void *) address_type;
	address = fn_ref_addr_create(&addr_id,
		strlen(data), (const void *) data);
	/* Construct the Reference */
	ref_id.format = FN_ID_STRING;
	ref_id.length = strlen(reference_type);
	ref_id.contents = (void *) reference_type;
	reference = fn_ref_create(&ref_id);
	/* Add Address to the Reference */
	fn_ref_append_addr(reference, address);
	
	/* Create a binding */
	fn_ctx_bind(initial_context, binding_name, reference, 0, status);
	/* Check the error status and return */
	return_status = fn_status_code(status);
	fn_composite_name_destroy(binding_name);
	fn_ref_addr_destroy(address);
	fn_ref_destroy(reference);
	fn_ctx_destroy(initial_context);
	return (return_status);
}

Listing and Working Wtih Object Attributes

The examples below show techniques to list and work with attributes of an object.

Listing an Object's Attributes

The example below shows how to list the attributes of an object.


#include <stdio.h>
#include <xfn/xfn.h>
/*
 This routine prints all the attributes associated
 with the named object to the standard output.
 Examples of using the function:
 	fns_attr_list("user/jsmith");
	fns_attr_list("thisorgunit/service/printer/color");
*/
void fns_attr_list(const char *name)
{
	FN_composite_name_t *name_comp;
	const FN_identifier_t *identifier;
	FN_attribute_t *attribute;
	const FN_attrvalue_t *values;
	char *id, *val;
	FN_multigetlist_t *attrset;
	void *ip;
	FN_status_t *status;
	FN_ctx_t *initial_context;
	name_comp = fn_composite_name_from_str((unsigned char *) name);
	status = fn_status_create();
	/* Obtain the initial context */
	initial_context = fn_ctx_handle_from_initial(0, status);
	if (!fn_status_is_success(status)) {
		fprintf(stderr, "Unable to obtain intial context\n");
		return;
	}
	/* Obtain all the attributes */
	attrset = fn_attr_multi_get(initial_context, name_comp, 0, 0,
            status);
	if (!fn_status_is_success(status)) {
		fprintf(stderr, "Unable to obtain attributes\n");
		return;
	}
	/* List all attributes */
	while (attribute = fn_multigetlist_next(attrset, status)) {
		identifier = fn_attribute_identifier(attribute);
		switch(identifier->format) {
		case FN_ID_STRING:
			id = (char *) malloc(identifier->length + 1);
			memcpy(id, identifier->contents, identifier->length);
			id[identifier->length] = '\0';
			printf("Attribute Identifier: %s", id);
			free(id);
			break;
		default:
			printf("Attribute of non-string format\n\n");
			continue;
		}
		for (values = fn_attribute_first(attribute, &ip);
		 values != NULL;
		 values = fn_attribute_next(attribute, &ip)) {
			val = (char *) malloc(values->length + 1);
			memcpy(val, values->contents, values->length);
			val[values->length] = '\0';
			printf("Value: %s", val);
			free(val);
		}
		fn_attribute_destroy(attribute);
		printf("\n");
	}
	fn_multigetlist_destroy(attrset);
	fn_ctx_destroy(initial_context);
	fn_status_destroy(status);
	fn_composite_name_destroy(name_comp);
}

Adding, Deleting, and Modifying an Object's Attributes

The example below shows how to add, delete, or modify an object's attributes.


#include <stdio.h>
#include <xfn/xfn.h>
/*
 This routine modifies an attribute associated
 with the named object. The modify operation supported are:
 	FN_ATTR_OP_ADD
 FN_ATTR_OP_ADD_EXCLUSIVE
 FN_ATTR_OP_REMOVE
 FN_ATTR_OP_ADD_VALUES
 FN_ATTR_OP_REMOVE_VALUES
 The function assumes the attribute values to be strings.
 Examples of using the function:
 The following function add an attribute of identifier "realname"
 with value "James Smith" to the user object "user/jsmith".
 	fns_attr_modify(
		"user/jsmith",
		"realname",
		"James Smith",
		FN_ATTR_OP_ADD);
 The following function removes an attribute of identifier 
 "location" from the printer object 
 "thisorgunit/service/printer/color".
 	fns_attr_modify(
		"thisorgunit/service/printer/color",
		"location",
		NULL,
		FN_ATTR_OP_REMOVE);
*/
static const char *attr_id_syntax = "fn_attr_syntax_ascii";
void fns_attr_modify(const char *name,
	const char *attr_id,
	const char *attr_value,
	unsigned int operation)
{
	FN_composite_name_t *name_comp;
	FN_identifier_t identifier, syntax;
	FN_attrvalue_t *values;
	FN_attribute_t *attribute;
	FN_status_t *status;
	FN_ctx_t *initial_context;
	name_comp = fn_composite_name_from_str((unsigned char *) name);
	status = fn_status_create();
	/* Obtain the initial context */
	initial_context = fn_ctx_handle_from_initial(0, status);
	if (!fn_status_is_success(status)) {
		fprintf(stderr, "Unable to obtain intial context\n");
		return;
	}
	/* Create the attribute to be added */
	/* First, the identifier */
	identifier.format = FN_ID_STRING;
	identifier.length = strlen(attr_id);
	identifier.contents = (void *) strdup(attr_id);
	/* Second, the syntax */
	syntax.format = FN_ID_STRING;
	syntax.length = strlen(attr_id_syntax);
	syntax.contents = (void *) strdup(attr_id_syntax);
	/* Third, the attribute value */
	if (attr_value) {
		values = (FN_attrvalue_t *) malloc(sizeof(FN_attrvalue_t));
		values->length = strlen(attr_value);
		values->contents = (void *) strdup(attr_value);
	} else
		values = NULL;
	/* Fourth, create the attribute */
	attribute = fn_attribute_create(&identifier, &syntax);
	/*Fifth, add the attribute value */
	if (values)
		fn_attribute_add(attribute, values, 0);
	
	/* Perform the XFN operation */
	fn_attr_modify(initial_context, name_comp, operation, attribute, 0,
status);
	if (!fn_status_is_success(status))
		fprintf(stderr, "Unable to perform attribute operation\n");
	fn_ctx_destroy(initial_context);
	fn_status_destroy(status);
	fn_composite_name_destroy(name_comp);
	fn_attibute_destroy(attribute);
	free(identifier.contents);
	free(syntax.contents);
	if (values) {
		free(values->contents);
		free(values);
 ]
]

Searching for Objects in a Context

The example below shows how to search for objects in a context with a specific attribute identifier and value.


#include <stdio.h>
#include <xfn/xfn.h>
#include <string.h>
#include <stdlib.h>
/*
 This routine searchs for objects in a context
 which has the specified attribute identifier and value.
*/
typedef struct fns_search_results {
	char *name;
	struct fns_search_results *next;
} fns_search_results;
static const char *attr_id_syntax = "fn_attr_syntax_ascii";
fns_search_results *
fns_attr_search(const char *name,
	const char *attr_id,
	const char *attr_value)
{
	FN_status_t *status;
	FN_ctx_t *initial_context;
	FN_composite_name_t *context_name;
	FN_searchlist_t *search_list;
	FN_string_t *search_name;
	FN_attribute_t *attribute;
	FN_attrset_t *attrset;
	FN_identifier_t identifier, syntax;
	FN_attrvalue_t *values;
	unsigned stat;
	fns_search_results *head = 0, *current, *prev;
	int no_names = 0;
	context_name = fn_composite_name_from_str((unsigned char *) name);
	status = fn_status_create();
	initial_context = fn_ctx_handle_from_initial(0, status);
	if (!fn_status_is_success(status)) {
		fprintf(stderr, "Unable to obtain intial context\n");
		return (0);
	}
	/* Construnct the attrset with attributes to be searched */
	/* First, the identifier */
	identifier.format = FN_ID_STRING;
	identifier.length = strlen(attr_id);
	identifier.contents = (void *) strdup(attr_id);
	/* Second, the syntax */
	syntax.format = FN_ID_STRING;
	syntax.length = strlen(attr_id_syntax);
	syntax.contents = (void *) strdup(attr_id_syntax);
	/* Third, the attribute value */
	values = (FN_attrvalue_t *) malloc(sizeof(FN_attrvalue_t));
	values->length = strlen(attr_value);
	values->contents = (void *) strdup(attr_value);
	/* Fourth, create the attribute */
	attribute = fn_attribute_create(&identifier, &syntax);
	/* Fifth, add the attribute value */
	fn_attribute_add(attribute, values, 0);
	/* Sixth, create attrset, and add the attribute */
	attrset = fn_attrset_create();
	fn_attrset_add(attrset, attribute, 0);
	search_list = prelim_fn_attr_search(initial_context,
	 context_name, attrset, 0, 0, status);
	if (!fn_status_is_success(status)) {
		fprintf(stderr, "Unable to list names\n");
		return (0);
	}
	while (search_name = prelim_fn_searchlist_next(search_list,
	 0, 0, status)) {
		no_names++;
		current = (fns_search_results *) 
    malloc(sizeof(fns_search_results));
		current->name = (char *)
		 malloc(strlen((char *) fn_string_str(search_name, &stat)) + 1);
		strcpy(current->name, (char *) fn_string_str(search_name, &stat));
		current->next = 0;
		if (head) {
			prev->next = current;
			prev = current;
		} else {
			head = current;
			prev = current;
		}
		fn_string_destroy(search_name);
	}
	fn_searchlist_destroy(search_list);
	fn_status_destroy(status);
	fn_ctx_destroy(initial_context);
	fn_attrset_destroy(attrset);
	fn_attribute_destroy(attribute);
	free(identifier.contents);
	free(syntax.contents);
	free(values->contents);
	free(values);
	return (head);
}