/*
* 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 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* This file contains public functions for managing DHCP network
* containers. For the semantics of these functions, please see the
* Enterprise DHCP Architecture Document.
*/
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <alloca.h>
#include <dhcp_svc_public.h>
#include <dirent.h>
#include <libgen.h>
#include <libinetutil.h>
#include "dhcp_network.h"
#include "util.h"
/* ARGSUSED */
int
{
unsigned int conver;
int retval;
int i, nelems;
char nl;
int fd;
return (DSVC_NO_MEMORY);
if (retval != DSVC_SUCCESS) {
return (retval);
}
return (DSVC_INTERNAL);
}
if (flags & DSVC_CREATE) {
/*
* We just created the per-network container; put the
* header on for future use...
*/
for (i = 0; connet[i] != '\0'; i++)
if (connet[i] == '.')
connet[i] = '_';
return (DSVC_INTERNAL);
}
} else {
/*
* Container already exists; sanity check against the
* header that's on-disk.
*/
for (i = 0; connet[i] != '\0'; i++)
if (connet[i] == '_')
connet[i] = '.';
return (DSVC_INTERNAL);
}
}
return (DSVC_SUCCESS);
}
int
{
return (DSVC_SUCCESS);
}
int
{
return (syserr_to_dsvcerr(errno));
return (DSVC_SUCCESS);
}
/*
* Internal version lookup routine used by both lookup_dn() and
* update_dn(); same semantics as lookup_dn() except that the `partial'
* argument has been generalized into a `flags' field.
*/
static int
{
unsigned int nfields;
/*
* Page the whole container into memory via mmap() so we can scan it
* quickly; map it MAP_PRIVATE so that we can change newlines to
* NULs without changing the actual container itself.
*/
return (DSVC_INTERNAL);
if (ent0 == MAP_FAILED)
return (DSVC_INTERNAL);
/*
* NUL-terminate the last byte (which should be a newline) so that
* we can safely use string functions on the mapped container.
*/
/*
* If we're searching by client IP address, then build a target
* string we can use to find it quickly.
*/
cip[0] = '\n';
}
/*
* Bail if we've reached the end of the container.
*/
break;
/*
* If we're searching by client IP address, locate it
* quickly using strstr(3C); if we can't find it by this
* technique then it's not in the container.
*/
/*
* If we've already found the DN_QCIP record, bail.
*/
if (nrecords > 0)
break;
break;
ent++;
}
/*
* Find the end of the record and change it a NUL byte so
* that it is interpreted correctly with field_split() and
* record_match() below. If we can't find a trailing
* newline, then it must be the last record (whose newline
* we already changed to a NUL above).
*/
*entend = '\0';
else
/*
* Skip pure comment lines; for now this just skips the
* header information at the top of the container.
*/
if (ent[0] == DNF_COMMENT_CHAR)
continue;
/*
* Split the buffer up into DNF_FIELDS fields.
*/
if (nfields < DNF_FIELDS)
continue;
/*
* See if we've got a match, filling in dnf.dnf_rec as
* we go. If record_match() succeeds, dnf.dnf_rec will
* be completely filled in.
*/
continue;
/*
* Caller just wants a count of the number of matching
* records, not the records themselves; continue.
*/
nrecords++;
continue;
}
/*
* Allocate record; if FIND_POSITION flag is set, then
* we need to allocate an extended (dn_recpos_t) record.
*/
if (flags & FIND_POSITION)
else
if ((flags & FIND_PARTIAL) == 0)
break;
}
/*
* Fill in record; do a structure copy from our automatic
* dn. If FIND_POSITION flag is on, pass back additional
* position information.
*/
if (flags & FIND_POSITION) {
}
/*
* Chuck the record on the list; up the counter.
*/
if (new_records == NULL) {
if ((flags & FIND_PARTIAL) == 0)
break;
}
nrecords++;
}
if (retval == DSVC_SUCCESS) {
return (DSVC_SUCCESS);
}
return (retval);
}
int
{
int retval;
int fd;
return (DSVC_ACCESS);
if (fd == -1)
return (syserr_to_dsvcerr(errno));
return (retval);
}
/*
* Compares the fields in fields[] agains the fields in target `targetp',
* using `query' to decide what fields to compare. Returns B_TRUE if `dnp'
* matches `targetp', B_FALSE if not. On success, `dnp' is completely
* filled in.
*/
static boolean_t
{
unsigned int i;
return (B_FALSE);
return (B_FALSE);
return (B_FALSE);
return (B_FALSE);
/*
* We use dn_cid_len since dnp->dn_cid_len is of type uchar_t but
* hexascii_to_octet() expects an uint_t *
*/
return (B_FALSE);
return (B_FALSE);
return (B_FALSE);
return (B_FALSE);
return (B_FALSE);
return (B_FALSE);
return (B_FALSE);
for (i = 0; i < sizeof (qflags) / sizeof (unsigned int); i++) {
return (B_FALSE);
return (B_FALSE);
}
sizeof (dnp->dn_comment));
return (B_TRUE);
}
/*
* Internal dhcp_network record update routine, used to factor out the
* common code between add_dn(), delete_dn(), and modify_dn(). If
* `origp' is NULL, then act like add_dn(); if `newp' is NULL, then
* act like delete_dn(); otherwise act like modify_dn().
*/
static int
{
int query;
return (DSVC_ACCESS);
/*
* Open the container to update and a new container file which we
* will store the updated version of the container in. When the
* update is done, rename the new file to be the real container.
*/
if (fd == -1)
return (syserr_to_dsvcerr(errno));
if (newfd == -1) {
return (syserr_to_dsvcerr(errno));
}
/*
* If we're changing the key for this record, make sure the key
* we're changing to doesn't already exist.
*/
if (retval != DSVC_SUCCESS)
goto out;
if (found != 0) {
goto out;
}
}
}
/*
* If we're adding a new record, make sure the record doesn't
* already exist.
*/
if (retval != DSVC_SUCCESS)
goto out;
if (found != 0) {
goto out;
}
}
/*
* If we're deleting or modifying record, make sure the record
* still exists and that our copy isn't stale. Note that we don't
* check signatures if we're deleting the record and origp->dn_sig
* is zero, so that records that weren't looked up can be deleted.
*/
&found);
if (retval != DSVC_SUCCESS)
goto out;
if (found == 0) {
retval = DSVC_NOENT;
goto out;
}
goto out;
}
}
/*
* Note the offset of the record we're modifying or deleting
* for use down below.
*/
} else {
/*
* No record to modify or delete, so set `recoff' and
* `recnext' appropriately.
*/
recoff = 0;
recnext = 0;
}
/*
* Make a new copy of the container. If we're deleting or
* modifying a record, don't copy that record to the new container.
*/
goto out;
}
if (retval != DSVC_SUCCESS)
goto out;
if (retval != DSVC_SUCCESS)
goto out;
/*
*/
else
if (retval != DSVC_SUCCESS)
goto out;
}
/*
* Note: we close these descriptors before the rename(2) (rather
* than just having the `out:' label clean them up) to save NFS
* some work (otherwise, NFS has to save `dnpath' to an alternate
* name since its vnode would still be active).
*/
return (retval);
out:
return (retval);
}
int
{
}
int
{
}
int
{
}
int
{
unsigned int i, count = 0;
int error;
switch (errno) {
case EACCES:
case EPERM:
return (DSVC_ACCESS);
case ENOENT:
return (DSVC_NO_LOCATION);
default:
break;
}
return (DSVC_INTERNAL);
}
/*
* Compile a regular expression matching "SUNWfilesX_" (where X is
* a container version number) followed by an IP address (roughly
* speaking). Note that the $N constructions allow us to get the
* container version and IP address when calling regex(3C).
*/
"(([0-9]{1,3}_){3}[0-9]{1,3})$1$", (char *)0);
return (DSVC_NO_MEMORY);
continue;
for (i = 0; ipaddr[i] != '\0'; i++)
if (ipaddr[i] == '_')
ipaddr[i] = '.';
(sizeof (char **)) * (count + 1));
if (new_listpp == NULL) {
goto fail;
}
listpp = new_listpp;
goto fail;
}
count++;
}
}
return (DSVC_SUCCESS);
fail:
for (i = 0; i < count; i++)
return (error);
}
/*
* Given a buffer `path' of `pathlen' bytes, fill it in with a path to the
* DHCP Network table for IP network `ip' located in directory `dir' with a
* suffix of `suffix'.
*/
static void
const char *suffix)
{
}
/*
* Write the dn_rec_t `recp' into the open container `fd' at offset
* `recoff'. Returns DSVC_* error code.
*/
static int
{
int entlen;
/*
* Copy data into a dn_filerec_t, since that's what we can
* actually put on disk.
*/
&cid_len) != 0)
return (DSVC_INTERNAL);
sizeof (dnf.dnf_comment));
if (entlen == -1)
return (syserr_to_dsvcerr(errno));
goto again;
}
return (syserr_to_dsvcerr(errno));
return (DSVC_SUCCESS);
}