nis_ns_proc.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 (c) 1990-2001 by Sun Microsystems, Inc.
* All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Ported from :
* "@(#)nis_ns_proc.c 1.15 91/03/01 Copyr 1990 Sun Micro";
*
*
* This module contains the actual implementation of NIS version 3.
* NB : It provides the routines that the dispatch function in nis_svc.c
* call. That file, nis_svc.c, is automatically generated and reflects the
* interface definition that is described in the nis.x file. When the
* nis.x file changes, you must make sure that any parameters that change
* get reflected in these routines.
*
* This module contains the Namespace manipulation procedures.
*/
#include <stdio.h>
#include <syslog.h>
#include <stdlib.h>
#include <rpc/auth_des.h>
#include "nis_proc.h"
extern bool_t xdr_nis_result();
extern nis_object* get_root_object();
extern nis_name __nis_local_root();
extern char *relative_name();
/*
* Handle the case in which we have the directory object but not its table.
* It is called when we try to lookup an item and get back a NIS_NOSUCHTABLE.
* On master, table should always exist; missing due to a mkdir failure
* master: create table & return (item) not found
* master & readonly: return system error
* On replica: indicates we have not seen directory's update yet.
* replica: add to pinglist and return NIS_NOT_ME
* replica & readonly: return NIS_NOT_ME
*/
{
if (readonly)
return (NIS_TRYAGAIN);
else {
/* create table */
NIS_SUCCESS) {
"Unable to create table %s: %s.",
return (status);
} else
return (NIS_SUCCESS);
}
} else {
/* replica */
if (!readonly) /* force update */
return (NIS_NOT_ME);
}
}
/*
* nis_lookup is the basic function used by clients of the name service.
* This function translates the request into an access of the local
* database.
*/
{
nis_object *d_obj = 0;
char pname[1024];
struct ticks t;
int read_dir, /* read access on directory */
read_obj; /* read access on an object */
char *p;
if (verbose)
__start_clock(0);
if (reqstp)
else
pname[0] = '\0';
int want_root;
if (!want_root)
else {
if (! root_server) {
/* maybe we have been added */
&t, 0, &d_obj);
else {
/* make copy to be returned */
}
} else {
d_obj = get_root_object();
}
if (d_obj) {
if (! read_dir) {
} else {
(char *)(d_obj),
"ns_lookup objects");
}
}
}
return (res);
}
free((void *)p);
/*
* Make sure we are allowed to READ this directory.
*
* POLICY: servers _must_ be able to read their own directory
* objects.
*/
return (res);
}
/* Look it up in the data base */
/* This means table of domain does not exist */
/* for sure, argp->ns_name will not be there */
}
if (read_dir) {
} else {
}
if (verbose)
return (res);
}
if (verbose)
"nis_lookup : exit status PERMISSION DENIED");
return (res);
}
if (verbose)
return (res);
}
/*
* Internal function that adds an object into the namespace.
*/
static void
*dobj;
{
directory_obj *d;
int i;
int add_ok = 0;
/*
* d points at the directory specific information
*/
else
return;
}
/*
* If we are adding a directory, make sure that it is a legitimate
* name, i.e. the new directory must be a descendant of the domain
* whose server is making this request. If we are in the root domain,
* then we can add a new directory object in the same domain.
*/
case LOWER_NAME:
break;
case SAME_NAME:
if (root_server) break;
default:
return;
}
}
/*
* Verify access rights. Check first to see if the directory object
* grants the right. If not, then check to see if the object access
* rights for that type of object grant the right. And if that
* doesn't then abort with PERMISSION denied.
*/
if (! add_ok) {
if (auth_verbose) {
"add_object : create DENIED by directory %s.%s",
}
for (i = 0; i < d->do_armask.do_armask_len; i++) {
if (auth_verbose) {
"add_object : create %s by object type.",
}
break;
}
}
} else if (auth_verbose) {
"add_object : create is ALLOWED by the directory.");
}
if (! add_ok) {
return;
}
/*
* Start the transaction, if we can't get an XID abort
*/
if (! xid) {
return;
}
/* Do the add operation */
else {
/* Notify replicates of the change. */
}
return;
}
/*
* Internal function that removes an object from the namespace.
*/
static void
*dobj;
{
directory_obj *d;
int i, rem_ok;
/*
* d points at the directory specific information
*/
return;
}
/* This is the existing object in the database */
return;
}
/*
* Verify delete access rights. Check first to see if the directory
* object grants the right. If not, then check to see if the object
* itself grants the right, then finally check to see of we have
* this access right for this type of object.
*/
if (auth_verbose) {
"remove_object : destroy %s by directory %s.%s",
}
if (! rem_ok) {
if (auth_verbose) {
"remove_object : destroy %s by object %s.%s",
}
}
if (! rem_ok) {
for (i = 0; i < d->do_armask.do_armask_len; i++) {
break;
}
}
}
if (! rem_ok) {
if (auth_verbose) {
"remove_object : destroy DENIED by object type.");
}
return;
} else if (auth_verbose) {
"remove_object : destroy ALLOWED by object type.");
}
/*
* Start the transaction, if we can't get an XID abort
*/
if (! xid) {
return;
}
/* Do the remove operation */
else {
/* Notify replicates of the change. */
/*
* No need to flush the caches - they have been flushed
* inside db_remove
*/
}
}
/* macro to get to the table column structures */
/*
* Internal function that modifies an object in the namespace.
*/
static void
*dobj;
{
directory_obj *d;
int i, mod_ok;
/*
* d points at the directory specific information
*/
return;
}
/* This is the existing object in the database */
/*
* Verify modify access rights. Check first to see if the directory
* object grants the right. If not, then check to see if the object
* itself grants the right, then finally check to see if we have
* this access right for this type of object.
*/
if (auth_verbose) {
"modify_object : modify %s by directory %s.%s",
}
if (! mod_ok) {
if (auth_verbose) {
"remove_object : modify %s by object %s.%s",
}
}
if (! mod_ok) {
for (i = 0; i < d->do_armask.do_armask_len; i++) {
if (auth_verbose) {
"modify_object : modify DENIED by object type.");
}
return;
} else {
if (auth_verbose) {
"modify_object : modify ALLOWED by object type.");
}
mod_ok = 1;
break;
}
}
}
}
/*
* if no one allows modify then fail.
*/
if (! mod_ok) {
return;
}
/*
* POLICY : Allow changing type ?
*
* ANSWER : No, only changing the meta data
* such as access etc is allowed.
*/
return;
}
return;
}
/*
* Start the transaction, if we can't get an XID abort
*/
if (! xid) {
return;
}
/*
* Now we generate a log entry with the old value so that if
* we crash, the transaction system can restore the object
* to its pre-modified state.
*/
add_update(&le);
return;
}
/*
* Data replacement of the variant part.
* NOTE: We play games with TABLE objects because we can't
* allow their schema to change on the fly. But there are
* fields in the table data that _can_ change such as the
* path of the table, separator character, and access rights.
*
* As in the case of ENTRY objects, we let the 'same oid' test be
* the signal that it is ok to overwrite these variables. This
* is overloading the OID value but I can't think of any other
* way to signal this operation without changing the protocol at
* this point.
*/
}
}
/*
* Now we add the object over the previous
* one. This instructs the database to
* discard the current one and replace it
* with our modified one. (And it's atomic)
*/
else {
/* Notify replicates of the change. */
/*
* No need to flush the caches - they have been flushed
* inside db_remove
*/
/*
* Send all the servers that serve this particular
* directory object a flush_cache message.
* We dont do this for group and table caches because
* they are served by those servers; and we can
* just hope that they get the updates real fast.
* For Directory objects, since we dont want the servers
* to throw out the cached directory objects and then go
* and refresh it with the stale copies, we will use
* TAG_DCACHE_ONE_REFRESH which will
* get a fresh copy of the object from the master.
*
* XXX: Since we are sending this message to all
* servers (including MASTER), this will lead to
* multiple calls to the master. One could have
* perhaps passed a modified directory object
* without the master.
*/
}
}
}
/*
* If prim and sec contain the same servers, return 0.
* If sec contains different servers than prim, result is set to:
* <all prim servers> <sec servers that are not in prim's list>
*/
static int
{
nis_server* answer = 0;
/* First count how many names in sec are different */
for (i = 0; i < ssize; i++) {
for (j = 0; j < psize; j++) {
break;
}
if (j == psize)
++diff;
}
if (diff == 0)
return (0);
/* different names were found on sec_server list */
if (answer == 0)
return (0);
/* Copy prim first */
for (i = 0; i < psize; i++)
answer[i] = prim_server[i];
newadd = i;
for (i = 0; i < ssize; i++) {
for (j = 0; j < psize; j++) {
break;
}
if (j == psize)
}
return (newsize);
}
static void
{
if (! oldroot) {
return;
}
/* updating non-data portion as well. */
/* somehow got an outdated copy of object. */
return;
} /* else, only interested in changing data portion. */
nis_server* merged_srvs = 0;
int howmany;
&merged_srvs);
/* howmany is 0 if new and old list are the same */
if (howmany > 0) {
}
&newroot,
&ping_list);
if (merged_srvs)
} else
} else
/* newroot just copies contents of other objects; need not be freed */
}
/*
* __nis_nameops()
*
* This code actually implements the operation that is requested.
* It is collected here in one place.
*/
static nis_result *
int op; /* operation to perform */
{
struct ticks t;
char optxt[32];
if (readonly) {
return (res);
}
if (auth_verbose) {
switch (op) {
case ADD_OP :
break;
case REM_OP :
break;
case MOD_OP :
break;
}
}
return (res);
}
/*
* don't allow an object to be added without an owner.
*/
return (res);
}
/*
* We have to handle the root object specially if we want to
* manipulate it using the NIS code.
*/
if (root_server &&
/* All we allow is a modify */
return (res);
}
return (res);
}
/*
* Fetch the directory object for this domain.
*/
return (res);
}
/*
* Get the last update time. If the current time is earlier
* someone has set the clock back which is very bad as far
* as NIS+ is concerned. This will catch almost all possible
* situations except the single second when time has finally
* caught up with the last entry in the log. Fixing this
* would require more radical changes to the whole update
* mechanism which is potentially risky and may even require
* protocol changes.
*/
"earlier than most recent log entry");
return (res);
}
switch (op) {
case ADD_OP :
break;
case REM_OP :
break;
case MOD_OP :
break;
}
return (res);
}
/*
* nis_add, this function will add a name to the name space if the
* permissions are allowed. The object that is about to be added to
* must allow "CREATE" access to the principal making the request.
*/
{
char pname[1024];
char *p;
__start_clock(0); /* Timing information */
if (verbose)
free((void *)p);
if (verbose)
return (res);
}
/*
* nis_modify, this function modifies the contents of the object that
* are named. It checks the MODIFY access right in the existing object
* and then does the operation.
*/
{
char pname[1024];
char *p = NULL;
__start_clock(0);
if (verbose)
if (p)
free((void *)p);
if (verbose)
return (res);
}
/*
* nis_remove removes and object from the name space. You will notice it
* shares a lot of code with the Add and remove functions.
*/
{
char *p;
__start_clock(0);
if (verbose)
free((void *)p);
/*
* If 'reqstp' is NULL, we're being called internally, and supply
* the local principal.
*/
if (reqstp != 0) {
} else {
}
if (verbose)
return (res);
}