common.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* This file contains functions, data shared among the two nisplus modules.
*/
#include <stdlib.h>
#include <unistd.h>
#include "common.h"
#include <string.h>
#include <sys/systeminfo.h>
#include "nisplus_impl.h"
/*
* Config file settings for NIS+ modules
*/
/*
* dhcptab table column description
*/
{ "key", TA_SEARCHABLE, 0 },
{ "flag", TA_SEARCHABLE, 0 },
{ "value", 0, 0 }
};
int
{
int dsvc_error;
switch (err) {
case NIS_SUCCESS: /* Success */
/* FALLTHRU */
case NIS_S_SUCCESS: /* Object retrieved successfully from cache */
break;
case NIS_NAMEEXISTS: /* Object with same name exists */
else
break;
case NIS_PERMISSION: /* Permission denied */
/* FALLTHRU */
case NIS_NOTOWNER: /* Not owner */
break;
case NIS_NOSUCHNAME: /* Not Found, no such name */
/* FALLTHRU */
case NIS_NOTFOUND: /* Not found */
/* FALLTHRU */
case NIS_S_NOTFOUND: /* Probably not found */
/* FALLTHRU */
switch (context) {
case DIRECTORY_OBJ:
break;
case TABLE_OBJ:
break;
case ENTRY_OBJ:
/* FALLTHRU */
default:
break;
}
break;
case NIS_NOSUCHTABLE: /* Database for table does not exist */
break;
case NIS_TRYAGAIN: /* Server busy, try again */
/* FALLTHRU */
case NIS_DUMPLATER: /* Master server busy, full dump rescheduled. */
break;
case NIS_UNKNOWNOBJ: /* Unknown object */
/* FALLTHRU */
case NIS_INVALIDOBJ: /* Invalid object for operation */
/* FALLTHRU */
case NIS_BADNAME: /* Malformed Name, or illegal name */
/* FALLTHRU */
case NIS_TYPEMISMATCH: /* Entry/Table type mismatch */
/* FALLTHRU */
case NIS_BADOBJECT: /* Illegal object type for operation */
/* FALLTHRU */
case NIS_BADATTRIBUTE: /* Missing or malformed attribute */
/* FALLTHRU */
case NIS_NOTSEARCHABLE: /* Named object is not searchable */
/* FALLTHRU */
case NIS_BADREQUEST: /* Query illegal for named table */
break;
case NIS_NOTSAMEOBJ: /* Passed object is not the same object */
/* on server */
break;
case NIS_UNAVAIL: /* NIS+ service unavailable / not installed */
/* FALLTHRU */
case NIS_COLDSTART_ERR: /* Error in accessing NIS+ cold start file */
/* FALLTHRU */
case NIS_NAMEUNREACHABLE: /* NIS+ servers unreachable */
break;
case NIS_NOFILESPACE: /* No file space on server */
/* FALLTHRU */
case NIS_NOPROC: /* Unable to create process on server */
/* FALLTHRU */
case NIS_NOCALLBACK: /* Unable to create callback */
break;
case NIS_NOMEMORY: /* Server out of memory */
break;
case NIS_SYSTEMERROR: /* Generic system error */
/* FALLTHRU */
case NIS_RPCERROR: /* Error in RPC subsystem */
/* FALLTHRU */
case NIS_FAIL: /* NIS+ operation failed */
/* FALLTHRU */
default:
break;
}
return (dsvc_error);
}
/*
* Return an dsvcnis_handle_t initialized with the arguments. Returns pointer
* to handle if successful, NULL otherwise. Caller is responsible for freeing
* the handle. Function copies arguments.
*/
{
return (NULL);
return (NULL);
}
return (NULL);
}
return (nhp);
}
/*
* Validate a NIS+ handle instance.
*/
{
sizeof (DSVC_NIS_COOKIE)) != 0)
return (B_FALSE);
return (B_TRUE);
}
/*
* Free a dsvcnis_handle_t.
*/
int
{
if (!dsvcnis_validate_handle(*nis_hpp))
return (DSVC_INVAL);
return (DSVC_SUCCESS);
}
/*
* Returns a copy of the type TABLE_OBJ in objpp for success,
* DSVC* error codes otherwise.
*/
int
{
int error;
HARD_LOOKUP | NO_CACHE);
if (error != DSVC_SUCCESS)
return (error);
else
} else
return (error);
}
/*
* Sets fields from TABLE_OBJ that is cached in handle.
*/
int
{
return (DSVC_NO_MEMORY);
}
return (DSVC_NO_MEMORY);
}
}
return (DSVC_NO_MEMORY);
}
}
return (DSVC_NO_MEMORY);
}
}
return (DSVC_SUCCESS);
}
/*
* Given a NISPLUS object, validate it, and return the nis_result.
* Directories must be absolute, as we don't want NIS+ to do any implicit
* expansion for us.
*/
int
{
int error;
return (DSVC_BAD_PATH);
return (error);
}
return (DSVC_BAD_PATH);
}
return (DSVC_SUCCESS);
}
/*
* Figure out who the owner will be of any object we create. Returns value
* in buf argument, which blen in size.
*/
int
{
/*
* Construct owner principal name and check existence.
* Set all access rights for owner.
* If user not specified, get process's real userid.
*/
} else
return (DSVC_NO_CRED);
/* Add domain name and trailing period to NIS name buffer */
}
/* Look up the NIS name in the specified domain's cred table */
user_dom = "";
return (DSVC_NO_CRED);
}
return (DSVC_SUCCESS);
}
/*
* Function to construct a NIS+ group name from groupname and domain.
* Must be a valid NIS+ group in the specified domain. Result is stored in buf,
* a buffer of blen in size.
*/
int
{
/*
* Construct group name if specified and check existence.
* If valid group, set all access rights for it.
* If group not specified, get default group from NIS_GROUP env var.
*/
group_nam = (char *)nis_local_group();
return (DSVC_NOENT); /* no group */
/* Add domain name and trailing dot to NIS group name buffer */
} else {
}
/* Look up group name in the specified domain */
buf[0] = '\0';
return (DSVC_NOENT);
}
return (DSVC_SUCCESS);
}
/*
* Given a access mask and desired access mode, check if the current user
* has the requested rights. This function is from
* function...
*/
{
pr = nis_local_principal();
return (B_TRUE);
return (B_FALSE);
}
/*
* Return a signature given an object instance
*/
{
}
/*
* Set an object instance id based upon a signature value
*/
void
{
}
/*
* Convert a nis_object ENTRY_OBJ to a dt_rec_t. Caller is responsible for
* freeing result.
*/
static int
{
return (DSVC_NO_MEMORY);
/* key */
/* flag */
/* value */
return (DSVC_NO_MEMORY);
}
/* OID -> signature */
return (DSVC_SUCCESS);
}
/*
* Convert a dt_rec_t into a nis_object ENTRY_OBJ. Table related fields will
* be filled in by the functions with the appropriate context. Caller is
* responsible for freeing result.
*/
static int
{
return (DSVC_NO_MEMORY);
return (DSVC_NO_MEMORY);
}
return (DSVC_NO_MEMORY);
}
/* key */
return (DSVC_NO_MEMORY);
}
/* flag */
return (DSVC_NO_MEMORY);
}
/* value */
return (DSVC_NO_MEMORY);
}
/* signature -> OID */
return (DSVC_SUCCESS);
}
/*
* Given a key and value, generate a nisplus query spec. Returns pointer to
* dynamically allocated query spec for success, NULL otherwise. Caller is
* responsible for freeing buffer.
*/
static char *
{
char *sp;
if (type == DSVCNIS_STR) {
return (NULL);
} else {
len += DSVC_QFMT_MAXINT;
return (NULL);
}
/* this shouldn't fail - we're giving memory back. */
}
return (sp);
}
/*
* memory. Returns DSVC_SUCCESS if the specification was appended to,
* DSVC_NO_MEMORY if no memory is to be found. Note that the scpp argument
* must point to a NULL if a new specification is to be built.
*/
int
void *valp)
{
int len;
return (DSVC_NO_MEMORY);
return (DSVC_SUCCESS);
}
return (DSVC_NO_MEMORY);
}
return (DSVC_SUCCESS);
}
/*
* Given a dt_rec_t and a query, generate a nisplus search criteria string.
* Returns dynamically allocated search criteria if successful, NULL otherwise
*/
static char *
{
/* only two fields are queryable, KEY and TYPE. */
}
char type_str[2];
}
if (err != DSVC_SUCCESS) {
return (NULL);
}
/* if this is a NULL query, allocate just enough for start spec */
return (NULL);
}
return (NULL);
}
return (scp);
}
/*
* Verify if nisplus is configured on this host. We do this by verifying that
* the local directory exists. If location happens to be non-null, we verify
* that the location is a valid directory object.
*/
int
{
int error;
return (DSVC_INTERNAL);
} else
if (error == DSVC_SUCCESS)
return (error);
}
/*
* Return the data store API version supported by this module. This version
* was implemented to support version 1 of the API.
*/
int
{
return (DSVC_SUCCESS);
}
/*
* NIS+ name space. There can be a hierarchy of directories, served on
* different servers (potentially). This hierarchy must be contiguous; once
* the root is uncovered, there cannot be non-existent subdirectories
* between the root and other existent subdirectories.
*
* Thus, the task at hand is to find the last directory server (farthest from
* the root), then create any required subdirectories on that server in order
* to produce the final directory where we'll be storing our table objects. The
* ability to create subdirectories on that server is of course dependent on
* whether we have the appropriate credentials.
*
* The directory argument must be absolute ('.' terminated). Otherwise, we
* risk some unhelpful magic that NIS+ might do underneath us.
*
* This function blocks if NIS+ is not available.
*/
int
mklocation(const char *directory)
{
unsigned int dlen;
int error = DSVC_SUCCESS;
/* Must be fully qualified */
return (DSVC_INVAL);
/* Find last directory server */
continue;
} else {
break; /* last */
}
}
return (DSVC_BAD_PATH); /* Invalid directory spec */
/*
* "lp" is last legal directory. We start there and move backward
* creating the children as we go.
*/
return (DSVC_EXISTS); /* directory already exists */
parent_dir = lp;
continue;
/* Get parent directory object */
for (;;) {
if (error == DSVC_SUCCESS)
break;
return (error);
(void) sleep(NIS_BUSY_PAUSE);
}
}
/*
* Convert directory into subdirectory. Preserve
* parent's attributes in child.
*/
return (DSVC_INVAL); /* not a directory */
}
return (DSVC_NO_MEMORY);
}
/* change the name */
return (DSVC_NO_MEMORY);
}
/* add new object to name space */
for (;;) {
if (error == DSVC_SUCCESS)
break;
return (error);
}
(void) sleep(NIS_BUSY_PAUSE);
}
/*
* Look up the new object. Really too bad that nis_add
* can't return an object.
*/
for (;;) {
if (error == DSVC_SUCCESS)
break;
return (error);
}
(void) sleep(NIS_BUSY_PAUSE);
}
/* create the associated directory */
for (;;) {
if (error == DSVC_SUCCESS)
break;
return (error);
}
(void) sleep(NIS_BUSY_PAUSE);
}
/* Now child becomes parent */
parent_dir = ep;
}
return (error);
}
/*
* List the current number of dhcptab container objects located at the
* NIS_DIRECTORY 'location' in listppp. Return number of list elements
* in 'count'. If no objects exist, then 'count' is set to 0 and
* DSVC_SUCCESS is returned.
*
* This function will block if NIS+ is unavailable.
*/
int
{
*count = 0;
&resp, HARD_LOOKUP);
if (error != DSVC_SUCCESS)
return (error);
for (;;) {
if (error == DSVC_SUCCESS)
break;
if (error == DSVC_NO_TABLE) {
/* Not having any containers is a fine result. */
return (DSVC_SUCCESS);
}
return (error);
(void) sleep(NIS_BUSY_PAUSE);
}
for (;;) {
(void) sleep(NIS_BUSY_PAUSE);
else
break;
}
if (terr != DSVC_SUCCESS)
continue;
sizeof (char **));
break;
}
} else
}
if (error != DSVC_SUCCESS) {
for (i = *count - 1; i >= 0; i--)
}
*count = 0;
}
return (error);
}
/*
* Creates or opens the "dhcptab" container in location and initializes
* handlep to point to the instance handle. When creating a new dhcptab, the
* caller's identity is used for owner/permissions. Performs any initialization
* needed by data store.
*/
int
{
int error;
location);
f_access |= NIS_READ_ACC;
if (flags & DSVC_WRITE)
if (flags & DSVC_CREATE) {
nis_object o;
(void) memset(&o, 0, sizeof (o));
sizeof (owner))) != DSVC_SUCCESS)
return (error);
sizeof (group))) != DSVC_SUCCESS)
o.zo_name = DT_TBL_NAME;
if (default_nis_access != 0)
if (default_nis_ttl == 0)
o.zo_ttl = NIS_DEF_TTL;
else
o.zo_ttl = default_nis_ttl;
if (error != DSVC_SUCCESS)
return (error);
}
&op);
if (error != DSVC_SUCCESS) {
return (error);
}
return (DSVC_ACCESS);
}
return (DSVC_NO_MEMORY);
return (DSVC_SUCCESS);
}
/*
* Frees instance handle, cleans up per instance state.
*/
int
{
}
/*
* Searches the dhcptab container for instances that match the query
* described by the combination of query and targetp. If the partial
* argument is true, then lookup operations that are unable to
* complete entirely are allowed (and considered successful). The
* query argument consists of 2 fields, each 16 bits long. The lower
* 16 bits selects which fields {key, flags} of targetp are to be
* considered in the query. The upper 16 bits identifies whether a
* particular field value must match (bit set) or not match (bit
* clear). Bits 2-15 in both 16 bit fields are currently unused, and
* must be set to 0. The count field specifies the maximum number of
* matching records to return, or -1 if any number of records may be
* returned. The recordspp argument is set to point to the resulting
* list of records; if recordspp is passed in as NULL then no records
* are actually returned. Note that these records are dynamically
* allocated, thus the caller is responsible for freeing them. The
* number of records found is returned in nrecordsp; a value of 0
* means that no records matched the query.
*/
int
{
char *scp;
int error, i;
if (!dsvcnis_validate_handle(nhp))
return (DSVC_INVAL);
return (DSVC_ACCESS);
return (DSVC_NO_MEMORY);
if (error != DSVC_SUCCESS) {
if (error == DSVC_NOENT) {
/* no records matched the query */
*nrecordsp = 0;
}
return (error);
}
/*
* Fastpath for queries w/o negative aspects for which no records are
* to be returned.
*/
return (DSVC_SUCCESS);
}
/*
* The query has gotten the records that match
* the "positive" aspects of the query. Weed out
* the records that match the "negative" aspect.
*/
continue;
if (error != DSVC_SUCCESS) {
if (partial)
break;
return (error);
}
if (partial)
break;
return (DSVC_NO_MEMORY);
} else {
num++;
}
}
return (DSVC_SUCCESS);
}
/*
* Add the record pointed to by to from the dhcptab container referred
* to by the handle. addp's signature will be updated by the
* underlying public module.
*/
int
{
nis_object *op;
int error;
if (!dsvcnis_validate_handle(nhp))
return (DSVC_INVAL);
return (DSVC_ACCESS);
return (error);
return (error);
}
for (;;) {
(void) sleep(NIS_BUSY_PAUSE);
} else
break;
}
if (error == DSVC_SUCCESS) {
/* oid -> signature */
}
return (error);
}
/*
* Atomically modify the record origp with the record newp in the
* dhcptab container referred to by the handle. newp's signature will
* be updated by the underlying public module. If an update collision
* occurs, no update of the data store occurs.
*/
int
{
char *scp;
int error;
if (!dsvcnis_validate_handle(nhp))
return (DSVC_INVAL);
return (DSVC_ACCESS);
/*
* MOD_SAMEOBJ ensures that the signature of the obj to modify has
* not changed in the table (detects update collisions).
*/
return (DSVC_NO_MEMORY);
return (error);
}
return (error);
}
return (error);
}
/* copy object ID */
/*
* We set MOD_EXCLUSIVE because the combination of
* key and type fields is unique, and we want nisplus
* to check to see if there would be a collision (matching
* record), and not perform the modify if a collision occurs.
* Allows us to do an atomic modify.
*/
flags |= MOD_EXCLUSIVE;
}
for (;;) {
(void) sleep(NIS_BUSY_PAUSE);
} else
break;
}
if (error == DSVC_SUCCESS)
return (error);
}
/*
* Delete the record referred to by dtp from the dhcptab container
* referred to by the handle. If an update collision occurs, no
* deletion of matching record in data store is done. Caller is
* responsible for freeing any dynamically allocated arguments.
*/
int
{
nis_object *op;
char *scp;
int error;
if (!dsvcnis_validate_handle(nhp))
return (DSVC_INVAL);
return (DSVC_ACCESS);
return (DSVC_NO_MEMORY);
/* Caller is interested in knowing about a collision */
if (error != DSVC_SUCCESS) {
return (error);
}
} else
for (;;) {
(void) sleep(NIS_BUSY_PAUSE);
else
break;
}
return (error);
}
/*
* Remove dhcptab container in location from data store
*
* This function blocks if NIS+ is unavailable.
*/
int
{
nis_object *op;
int err;
location);
/* Empty the entire table */
for (;;) {
break;
return (err);
(void) sleep(NIS_BUSY_PAUSE);
}
/* now remove the table */
for (;;) {
if (err == DSVC_SUCCESS)
break;
return (err);
(void) sleep(NIS_BUSY_PAUSE);
}
for (;;) {
break;
(void) sleep(NIS_BUSY_PAUSE);
}
return (err);
}
/*
* Frees instance handle, cleans up per instance state.
*/
int
{
}