PageRenderTime 75ms CodeModel.GetById 2ms app.highlight 66ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/bsnmp/snmp_vacm/vacm_snmp.c

https://bitbucket.org/freebsd/freebsd-head/
C | 1026 lines | 825 code | 152 blank | 49 comment | 252 complexity | 0ad31082f915f1767a92a63044ac544a MD5 | raw file
   1/*-
   2 * Copyright (c) 2010 The FreeBSD Foundation
   3 * All rights reserved.
   4 *
   5 * This software was developed by Shteryana Sotirova Shopova under
   6 * sponsorship from the FreeBSD Foundation.
   7 *
   8 * Redistribution and use in source and binary forms, with or without
   9 * modification, are permitted provided that the following conditions
  10 * are met:
  11 * 1. Redistributions of source code must retain the above copyright
  12 *    notice, this list of conditions and the following disclaimer.
  13 * 2. Redistributions in binary form must reproduce the above copyright
  14 *    notice, this list of conditions and the following disclaimer in the
  15 *    documentation and/or other materials provided with the distribution.
  16 *
  17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27 * SUCH DAMAGE.
  28 *
  29 * $FreeBSD$
  30 */
  31#include <sys/queue.h>
  32#include <sys/types.h>
  33
  34#include <errno.h>
  35#include <stdarg.h>
  36#include <stdlib.h>
  37#include <stdio.h>
  38#include <stdint.h>
  39#include <string.h>
  40#include <syslog.h>
  41
  42#include "asn1.h"
  43#include "snmp.h"
  44#include "snmpmod.h"
  45
  46#include "vacm_tree.h"
  47#include "vacm_oid.h"
  48
  49static struct lmodule *vacm_module;
  50/* For the registration. */
  51static const struct asn_oid oid_vacm = OIDX_snmpVacmMIB;
  52
  53static uint reg_vacm;
  54
  55static int32_t vacm_lock;
  56
  57/*
  58 * Internal datastructures and forward declarations.
  59 */
  60static void		vacm_append_userindex(struct asn_oid *,
  61    uint, const struct vacm_user *);
  62static int		vacm_user_index_decode(const struct asn_oid *,
  63    uint, int32_t *, char *);
  64static struct vacm_user *vacm_get_user(const struct asn_oid *,
  65    uint);
  66static struct vacm_user *vacm_get_next_user(const struct asn_oid *,
  67    uint);
  68static void		vacm_append_access_rule_index(struct asn_oid *,
  69    uint, const struct vacm_access *);
  70static int		vacm_access_rule_index_decode(const struct asn_oid *,
  71    uint, char *, char *, int32_t *, int32_t *);
  72static struct vacm_access *	vacm_get_access_rule(const struct asn_oid *,
  73    uint);
  74static struct vacm_access *	vacm_get_next_access_rule(const struct asn_oid *,
  75    uint);
  76static int		vacm_view_index_decode(const struct asn_oid *, uint,
  77    char *, struct asn_oid *);
  78static void		vacm_append_viewindex(struct asn_oid *, uint,
  79    const struct vacm_view *);
  80static struct vacm_view	*vacm_get_view(const struct asn_oid *, uint);
  81static struct vacm_view	*vacm_get_next_view(const struct asn_oid *, uint);
  82static struct vacm_view *vacm_get_view_by_name(u_char *, u_int);
  83static struct vacm_context	*vacm_get_context(const struct asn_oid *, uint);
  84static struct vacm_context	*vacm_get_next_context(const struct asn_oid *,
  85    uint);
  86static void			vacm_append_ctxindex(struct asn_oid *, uint,
  87    const struct vacm_context *);
  88
  89int
  90op_vacm_context(struct snmp_context *ctx __unused, struct snmp_value *val,
  91    uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
  92{
  93	char cname[SNMP_ADM_STR32_SIZ];
  94	size_t cnamelen;
  95	struct vacm_context *vacm_ctx;
  96
  97	if (val->var.subs[sub - 1] != LEAF_vacmContextName)
  98		abort();
  99
 100	switch (op) {
 101	case SNMP_OP_GET:
 102		if ((vacm_ctx = vacm_get_context(&val->var, sub)) == NULL)
 103			return (SNMP_ERR_NOSUCHNAME);
 104		break;
 105
 106	case SNMP_OP_GETNEXT:
 107		if ((vacm_ctx = vacm_get_next_context(&val->var, sub)) == NULL)
 108			return (SNMP_ERR_NOSUCHNAME);
 109		vacm_append_ctxindex(&val->var, sub, vacm_ctx);
 110		break;
 111
 112	case SNMP_OP_SET:
 113		if ((vacm_ctx = vacm_get_context(&val->var, sub)) != NULL)
 114			return (SNMP_ERR_WRONG_VALUE);
 115		if (community != COMM_INITIALIZE)
 116			return (SNMP_ERR_NOT_WRITEABLE);
 117		if (val->var.subs[sub] >= SNMP_ADM_STR32_SIZ)
 118			return (SNMP_ERR_WRONG_VALUE);
 119		if (index_decode(&val->var, sub, iidx, &cname, &cnamelen))
 120			return (SNMP_ERR_GENERR);
 121		cname[cnamelen] = '\0';
 122		if ((vacm_ctx = vacm_add_context(cname, reg_vacm)) == NULL)
 123			return (SNMP_ERR_GENERR);
 124		return (SNMP_ERR_NOERROR);
 125
 126	case SNMP_OP_COMMIT:
 127		/* FALLTHROUGH*/
 128	case SNMP_OP_ROLLBACK:
 129		return (SNMP_ERR_NOERROR);
 130	default:
 131		abort();
 132	}
 133
 134	return (string_get(val, vacm_ctx->ctxname, -1));
 135}
 136
 137int
 138op_vacm_security_to_group(struct snmp_context *ctx, struct snmp_value *val,
 139    uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
 140{
 141	int32_t smodel;
 142	char uname[SNMP_ADM_STR32_SIZ];
 143	struct vacm_user *user;
 144
 145	switch (op) {
 146	case SNMP_OP_GET:
 147		if ((user = vacm_get_user(&val->var, sub)) == NULL)
 148			return (SNMP_ERR_NOSUCHNAME);
 149		break;
 150
 151	case SNMP_OP_GETNEXT:
 152		if ((user = vacm_get_next_user(&val->var, sub)) == NULL)
 153			return (SNMP_ERR_NOSUCHNAME);
 154		vacm_append_userindex(&val->var, sub, user);
 155		break;
 156
 157	case SNMP_OP_SET:
 158		if ((user = vacm_get_user(&val->var, sub)) == NULL &&
 159		    val->var.subs[sub - 1] != LEAF_vacmSecurityToGroupStatus)
 160			return (SNMP_ERR_NOSUCHNAME);
 161
 162		if (user != NULL) {
 163			if (community != COMM_INITIALIZE &&
 164			    user->type == StorageType_readOnly)
 165				return (SNMP_ERR_NOT_WRITEABLE);
 166			if (user->status == RowStatus_active &&
 167			    val->v.integer != RowStatus_destroy)
 168				return (SNMP_ERR_INCONS_VALUE);
 169		}
 170
 171		switch (val->var.subs[sub - 1]) {
 172		case LEAF_vacmGroupName:
 173			ctx->scratch->ptr1 = user->group->groupname;
 174			ctx->scratch->int1 = strlen(user->group->groupname);
 175			return (vacm_user_set_group(user,
 176			    val->v.octetstring.octets,val->v.octetstring.len));
 177
 178		case LEAF_vacmSecurityToGroupStorageType:
 179			return (SNMP_ERR_INCONS_VALUE);
 180
 181		case LEAF_vacmSecurityToGroupStatus:
 182			if (user == NULL) {
 183				if (val->v.integer != RowStatus_createAndGo ||
 184				    vacm_user_index_decode(&val->var, sub,
 185				    &smodel, uname) < 0)
 186					return (SNMP_ERR_INCONS_VALUE);
 187				user = vacm_new_user(smodel, uname);
 188				if (user == NULL)
 189					return (SNMP_ERR_GENERR);
 190				user->status = RowStatus_destroy;
 191				if (community != COMM_INITIALIZE)
 192					user->type = StorageType_volatile;
 193				else
 194					user->type = StorageType_readOnly;
 195			} else if (val->v.integer != RowStatus_active &&
 196			    val->v.integer != RowStatus_destroy)
 197				return (SNMP_ERR_INCONS_VALUE);
 198			ctx->scratch->int1 = user->status;
 199			user->status = val->v.integer;
 200			break;
 201		}
 202		return (SNMP_ERR_NOERROR);
 203
 204	case SNMP_OP_COMMIT:
 205		if (val->var.subs[sub - 1] != LEAF_vacmSecurityToGroupStatus)
 206			return (SNMP_ERR_NOERROR);
 207		if ((user = vacm_get_user(&val->var, sub)) == NULL)
 208			return (SNMP_ERR_GENERR);
 209		switch (val->v.integer) {
 210		case  RowStatus_destroy:
 211			return (vacm_delete_user(user));
 212
 213		case RowStatus_createAndGo:
 214			user->status = RowStatus_active;
 215			break;
 216
 217		default:
 218			break;
 219		}
 220		return (SNMP_ERR_NOERROR);
 221
 222	case SNMP_OP_ROLLBACK:
 223		if ((user = vacm_get_user(&val->var, sub)) == NULL)
 224			return (SNMP_ERR_GENERR);
 225		switch (val->var.subs[sub - 1]) {
 226		case LEAF_vacmGroupName:
 227			return (vacm_user_set_group(user, ctx->scratch->ptr1,
 228			    ctx->scratch->int1));
 229
 230		case LEAF_vacmSecurityToGroupStatus:
 231			if (ctx->scratch->int1 == RowStatus_destroy)
 232				return (vacm_delete_user(user));
 233			user->status = ctx->scratch->int1;
 234			break;
 235
 236		default:
 237			break;
 238		}
 239		return (SNMP_ERR_NOERROR);
 240
 241	default:
 242		abort();
 243	}
 244
 245	switch (val->var.subs[sub - 1]) {
 246	case LEAF_vacmGroupName:
 247		return (string_get(val, user->group->groupname, -1));
 248	case LEAF_vacmSecurityToGroupStorageType:
 249		val->v.integer = user->type;
 250		break;
 251	case LEAF_vacmSecurityToGroupStatus:
 252		val->v.integer = user->status;
 253		break;
 254	default:
 255		abort();
 256	}
 257
 258	return (SNMP_ERR_NOERROR);
 259}
 260
 261int
 262op_vacm_access(struct snmp_context *ctx, struct snmp_value *val, uint32_t sub,
 263    uint32_t iidx __unused, enum snmp_op op)
 264{
 265	int32_t smodel, slevel;
 266	char gname[SNMP_ADM_STR32_SIZ], cprefix[SNMP_ADM_STR32_SIZ];
 267	struct vacm_access *acl;
 268
 269	switch (op) {
 270	case SNMP_OP_GET:
 271		if ((acl = vacm_get_access_rule(&val->var, sub)) == NULL)
 272			return (SNMP_ERR_NOSUCHNAME);
 273		break;
 274
 275	case SNMP_OP_GETNEXT:
 276		if ((acl = vacm_get_next_access_rule(&val->var, sub)) == NULL)
 277			return (SNMP_ERR_NOSUCHNAME);
 278		vacm_append_access_rule_index(&val->var, sub, acl);
 279		break;
 280
 281	case SNMP_OP_SET:
 282		if ((acl = vacm_get_access_rule(&val->var, sub)) == NULL &&
 283		    val->var.subs[sub - 1] != LEAF_vacmAccessStatus)
 284				return (SNMP_ERR_NOSUCHNAME);
 285		if (acl != NULL && community != COMM_INITIALIZE &&
 286		    acl->type == StorageType_readOnly)
 287			return (SNMP_ERR_NOT_WRITEABLE);
 288
 289		switch (val->var.subs[sub - 1]) {
 290		case LEAF_vacmAccessContextMatch:
 291			ctx->scratch->int1 = acl->ctx_match;
 292			if (val->v.integer == vacmAccessContextMatch_exact)
 293				acl->ctx_match = 1;
 294			else if (val->v.integer == vacmAccessContextMatch_prefix)
 295				acl->ctx_match = 0;
 296			else
 297				return (SNMP_ERR_WRONG_VALUE);
 298			break;
 299
 300		case LEAF_vacmAccessReadViewName:
 301			ctx->scratch->ptr1 = acl->read_view;
 302			acl->read_view = vacm_get_view_by_name(val->v.octetstring.octets, val->v.octetstring.len);
 303			if (acl->read_view == NULL) {
 304				acl->read_view = ctx->scratch->ptr1;
 305				return (SNMP_ERR_INCONS_VALUE);
 306			}
 307			return (SNMP_ERR_NOERROR);
 308
 309		case LEAF_vacmAccessWriteViewName:
 310			ctx->scratch->ptr1 = acl->write_view;
 311			if ((acl->write_view =
 312			    vacm_get_view_by_name(val->v.octetstring.octets,
 313			    val->v.octetstring.len)) == NULL) {
 314				acl->write_view = ctx->scratch->ptr1;
 315				return (SNMP_ERR_INCONS_VALUE);
 316			}
 317			break;
 318
 319		case LEAF_vacmAccessNotifyViewName:
 320			ctx->scratch->ptr1 = acl->notify_view;
 321			if ((acl->notify_view =
 322			    vacm_get_view_by_name(val->v.octetstring.octets,
 323			    val->v.octetstring.len)) == NULL) {
 324				acl->notify_view = ctx->scratch->ptr1;
 325				return (SNMP_ERR_INCONS_VALUE);
 326			}
 327			break;
 328
 329		case LEAF_vacmAccessStorageType:
 330			return (SNMP_ERR_INCONS_VALUE);
 331
 332		case LEAF_vacmAccessStatus:
 333			if (acl == NULL) {
 334				if (val->v.integer != RowStatus_createAndGo ||
 335				    vacm_access_rule_index_decode(&val->var,
 336				    sub, gname, cprefix, &smodel, &slevel) < 0)
 337					return (SNMP_ERR_INCONS_VALUE);
 338				if ((acl = vacm_new_access_rule(gname, cprefix,
 339				    smodel, slevel)) == NULL)
 340					return (SNMP_ERR_GENERR);
 341				acl->status = RowStatus_destroy;
 342				if (community != COMM_INITIALIZE)
 343					acl->type = StorageType_volatile;
 344				else
 345					acl->type = StorageType_readOnly;
 346			} else if (val->v.integer != RowStatus_active &&
 347			    val->v.integer != RowStatus_destroy)
 348				return (SNMP_ERR_INCONS_VALUE);
 349			ctx->scratch->int1 = acl->status;
 350			acl->status = val->v.integer;
 351			break;
 352		}
 353		return (SNMP_ERR_NOERROR);
 354
 355	case SNMP_OP_COMMIT:
 356		if (val->var.subs[sub - 1] != LEAF_vacmAccessStatus)
 357			return (SNMP_ERR_NOERROR);
 358		if ((acl = vacm_get_access_rule(&val->var, sub)) == NULL)
 359			return (SNMP_ERR_GENERR);
 360		if (val->v.integer == RowStatus_destroy)
 361			return (vacm_delete_access_rule(acl));
 362		else
 363			acl->status = RowStatus_active;
 364		return (SNMP_ERR_NOERROR);
 365
 366	case SNMP_OP_ROLLBACK:
 367		if ((acl = vacm_get_access_rule(&val->var, sub)) == NULL)
 368			return (SNMP_ERR_GENERR);
 369		switch (val->var.subs[sub - 1]) {
 370		case LEAF_vacmAccessContextMatch:
 371			acl->ctx_match = ctx->scratch->int1;
 372			break;
 373		case LEAF_vacmAccessReadViewName:
 374			acl->read_view = ctx->scratch->ptr1;
 375			break;
 376		case LEAF_vacmAccessWriteViewName:
 377			acl->write_view = ctx->scratch->ptr1;
 378			break;
 379		case LEAF_vacmAccessNotifyViewName:
 380			acl->notify_view = ctx->scratch->ptr1;
 381			break;
 382		case LEAF_vacmAccessStatus:
 383			if (ctx->scratch->int1 == RowStatus_destroy)
 384				return (vacm_delete_access_rule(acl));
 385		default:
 386			break;
 387		}
 388		return (SNMP_ERR_NOERROR);
 389
 390	default:
 391		abort();
 392	}
 393
 394	switch (val->var.subs[sub - 1]) {
 395	case LEAF_vacmAccessContextMatch:
 396		return (string_get(val, acl->ctx_prefix, -1));
 397	case LEAF_vacmAccessReadViewName:
 398		if (acl->read_view != NULL)
 399			return (string_get(val, acl->read_view->viewname, -1));
 400		else
 401			return (string_get(val, NULL, 0));
 402	case LEAF_vacmAccessWriteViewName:
 403		if (acl->write_view != NULL)
 404			return (string_get(val, acl->write_view->viewname, -1));
 405		else
 406			return (string_get(val, NULL, 0));
 407	case LEAF_vacmAccessNotifyViewName:
 408		if (acl->notify_view != NULL)
 409			return (string_get(val, acl->notify_view->viewname, -1));
 410		else
 411			return (string_get(val, NULL, 0));
 412	case LEAF_vacmAccessStorageType:
 413		val->v.integer = acl->type;
 414		break;
 415	case LEAF_vacmAccessStatus:
 416		val->v.integer = acl->status;
 417		break;
 418	default:
 419		abort();
 420	}
 421
 422	return (SNMP_ERR_NOERROR);
 423}
 424
 425int
 426op_vacm_view_lock(struct snmp_context *ctx __unused, struct snmp_value *val,
 427    uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
 428{
 429	if (val->var.subs[sub - 1] != LEAF_vacmViewSpinLock)
 430		return (SNMP_ERR_NOSUCHNAME);
 431
 432	switch (op) {
 433	case SNMP_OP_GET:
 434		if (++vacm_lock == INT32_MAX)
 435			vacm_lock = 0;
 436		val->v.integer = vacm_lock;
 437		break;
 438
 439	case SNMP_OP_GETNEXT:
 440		abort();
 441
 442	case SNMP_OP_SET:
 443		if (val->v.integer != vacm_lock)
 444			return (SNMP_ERR_INCONS_VALUE);
 445		break;
 446
 447	case SNMP_OP_ROLLBACK:
 448		/* FALLTHROUGH */
 449	case SNMP_OP_COMMIT:
 450		break;
 451	}
 452
 453	return (SNMP_ERR_NOERROR);
 454}
 455
 456int
 457op_vacm_view(struct snmp_context *ctx, struct snmp_value *val, uint32_t sub,
 458    uint32_t iidx __unused, enum snmp_op op)
 459{
 460	char vname[SNMP_ADM_STR32_SIZ];
 461	struct asn_oid oid;
 462	struct vacm_view *view;
 463
 464	switch (op) {
 465	case SNMP_OP_GET:
 466		if ((view = vacm_get_view(&val->var, sub)) == NULL)
 467			return (SNMP_ERR_NOSUCHNAME);
 468		break;
 469
 470	case SNMP_OP_GETNEXT:
 471		if ((view = vacm_get_next_view(&val->var, sub)) == NULL)
 472			return (SNMP_ERR_NOSUCHNAME);
 473		vacm_append_viewindex(&val->var, sub, view);
 474		break;
 475
 476	case SNMP_OP_SET:
 477		if ((view = vacm_get_view(&val->var, sub)) == NULL &&
 478		    val->var.subs[sub - 1] != LEAF_vacmViewTreeFamilyStatus)
 479				return (SNMP_ERR_NOSUCHNAME);
 480
 481		if (view != NULL) {
 482			if (community != COMM_INITIALIZE &&
 483			    view->type == StorageType_readOnly)
 484				return (SNMP_ERR_NOT_WRITEABLE);
 485			if (view->status == RowStatus_active &&
 486			    val->v.integer != RowStatus_destroy)
 487				return (SNMP_ERR_INCONS_VALUE);
 488		}
 489
 490		switch (val->var.subs[sub - 1]) {
 491		case LEAF_vacmViewTreeFamilyMask:
 492			if (val->v.octetstring.len > sizeof(view->mask))
 493			ctx->scratch->ptr1 = malloc(sizeof(view->mask));
 494			if (ctx->scratch->ptr1 == NULL)
 495				return (SNMP_ERR_GENERR);
 496			memset(ctx->scratch->ptr1, 0, sizeof(view->mask));
 497			memcpy(ctx->scratch->ptr1, view->mask,
 498			    sizeof(view->mask));
 499			memset(view->mask, 0, sizeof(view->mask));
 500			memcpy(view->mask, val->v.octetstring.octets,
 501			    val->v.octetstring.len);
 502			break;
 503
 504		case LEAF_vacmViewTreeFamilyType:
 505			ctx->scratch->int1 = view->exclude;
 506			if (val->v.integer == vacmViewTreeFamilyType_included)
 507				view->exclude = 0;
 508			else if (val->v.integer == vacmViewTreeFamilyType_excluded)
 509				view->exclude = 1;
 510			else
 511				return (SNMP_ERR_WRONG_VALUE);
 512			break;
 513
 514		case LEAF_vacmViewTreeFamilyStorageType:
 515			return (SNMP_ERR_INCONS_VALUE);
 516
 517		case LEAF_vacmViewTreeFamilyStatus:
 518			if (view == NULL) {
 519				if (val->v.integer != RowStatus_createAndGo ||
 520				    vacm_view_index_decode(&val->var, sub, vname,
 521				    &oid) < 0)
 522					return (SNMP_ERR_INCONS_VALUE);
 523				if ((view = vacm_new_view(vname, &oid)) == NULL)
 524					return (SNMP_ERR_GENERR);
 525				view->status = RowStatus_destroy;
 526				if (community != COMM_INITIALIZE)
 527					view->type = StorageType_volatile;
 528				else
 529					view->type = StorageType_readOnly;
 530			} else if (val->v.integer != RowStatus_active &&
 531			    val->v.integer != RowStatus_destroy)
 532				return (SNMP_ERR_INCONS_VALUE);
 533			ctx->scratch->int1 = view->status;
 534			view->status = val->v.integer;
 535			break;
 536		}
 537		return (SNMP_ERR_NOERROR);
 538
 539	case SNMP_OP_COMMIT:
 540		switch (val->var.subs[sub - 1]) {
 541		case LEAF_vacmViewTreeFamilyMask:
 542			free(ctx->scratch->ptr1);
 543			break;
 544		case LEAF_vacmViewTreeFamilyStatus:
 545			if ((view = vacm_get_view(&val->var, sub)) == NULL)
 546				return (SNMP_ERR_GENERR);
 547			switch (val->v.integer) {
 548			case  RowStatus_destroy:
 549				return (vacm_delete_view(view));
 550
 551			case RowStatus_createAndGo:
 552				view->status = RowStatus_active;
 553				break;
 554
 555			default:
 556				/* NOTREACHED*/
 557				return (SNMP_ERR_GENERR);
 558			}
 559		default:
 560			break;
 561		}
 562		return (SNMP_ERR_NOERROR);
 563
 564	case SNMP_OP_ROLLBACK:
 565		if ((view = vacm_get_view(&val->var, sub)) == NULL)
 566			return (SNMP_ERR_GENERR);
 567		switch (val->var.subs[sub - 1]) {
 568		case LEAF_vacmViewTreeFamilyMask:
 569			memcpy(view->mask, ctx->scratch->ptr1,
 570			    sizeof(view->mask));
 571			free(ctx->scratch->ptr1);
 572			break;
 573		case LEAF_vacmViewTreeFamilyType:
 574			view->exclude = ctx->scratch->int1;
 575			break;
 576		case LEAF_vacmViewTreeFamilyStatus:
 577			if (ctx->scratch->int1 == RowStatus_destroy)
 578				return (vacm_delete_view(view));
 579			break;
 580		default:
 581			break;	
 582		}
 583		return (SNMP_ERR_NOERROR);
 584
 585	default:
 586		abort();
 587	}
 588
 589	switch (val->var.subs[sub - 1]) {
 590	case LEAF_vacmViewTreeFamilyMask:
 591		return (string_get(val, view->mask, sizeof(view->mask)));
 592	case LEAF_vacmViewTreeFamilyType:
 593		if (view->exclude)
 594			val->v.integer = vacmViewTreeFamilyType_excluded;
 595		else
 596			val->v.integer = vacmViewTreeFamilyType_included;
 597		break;
 598	case LEAF_vacmViewTreeFamilyStorageType:
 599		val->v.integer = view->type;
 600		break;
 601	case LEAF_vacmViewTreeFamilyStatus:
 602		val->v.integer = view->status;
 603		break;
 604	default:
 605		abort();
 606	}
 607
 608	return (SNMP_ERR_NOERROR);
 609}
 610
 611static void
 612vacm_append_userindex(struct asn_oid *oid, uint sub,
 613    const struct vacm_user *user)
 614{
 615	uint32_t i;
 616
 617	oid->len = sub + strlen(user->secname) + 2;
 618	oid->subs[sub++] = user->sec_model;
 619	oid->subs[sub] = strlen(user->secname);
 620	for (i = 1; i <= strlen(user->secname); i++)
 621		oid->subs[sub + i] = user->secname[i - 1];
 622}
 623
 624static int
 625vacm_user_index_decode(const struct asn_oid *oid, uint sub,
 626    int32_t *smodel, char *uname)
 627{
 628	uint32_t i;
 629
 630	*smodel = oid->subs[sub++];
 631
 632	if (oid->subs[sub] >= SNMP_ADM_STR32_SIZ)
 633		return (-1);
 634
 635	for (i = 0; i < oid->subs[sub]; i++)
 636		uname[i] = oid->subs[sub + i + 1];
 637	uname[i] = '\0';
 638
 639	return (0);
 640}
 641
 642static struct vacm_user *
 643vacm_get_user(const struct asn_oid *oid, uint sub)
 644{
 645	int32_t smodel;
 646	char uname[SNMP_ADM_STR32_SIZ];
 647	struct vacm_user *user;
 648
 649	if (vacm_user_index_decode(oid, sub, &smodel, uname) < 0)
 650		return (NULL);
 651
 652	for (user = vacm_first_user(); user != NULL; user = vacm_next_user(user))
 653		if (strcmp(uname, user->secname) == 0 &&
 654		    user->sec_model == smodel)
 655			return (user);
 656
 657	return (NULL);
 658}
 659
 660static struct vacm_user *
 661vacm_get_next_user(const struct asn_oid *oid, uint sub)
 662{
 663	int32_t smodel;
 664	char uname[SNMP_ADM_STR32_SIZ];
 665	struct vacm_user *user;
 666
 667	if (oid->len - sub == 0)
 668		return (vacm_first_user());
 669
 670	if (vacm_user_index_decode(oid, sub, &smodel, uname) < 0)
 671		return (NULL);
 672
 673	for (user = vacm_first_user(); user != NULL; user = vacm_next_user(user))
 674		if (strcmp(uname, user->secname) == 0 &&
 675		    user->sec_model == smodel)
 676			return (vacm_next_user(user));
 677
 678	return (NULL);
 679}
 680
 681static void
 682vacm_append_access_rule_index(struct asn_oid *oid, uint sub,
 683    const struct vacm_access *acl)
 684{
 685	uint32_t i;
 686  
 687	oid->len = sub + strlen(acl->group->groupname) +
 688	    strlen(acl->ctx_prefix) + 4;
 689
 690	oid->subs[sub] = strlen(acl->group->groupname);
 691	for (i = 1; i <= strlen(acl->group->groupname); i++)
 692		oid->subs[sub + i] = acl->group->groupname[i - 1];
 693	sub += strlen(acl->group->groupname) + 1;
 694
 695	oid->subs[sub] = strlen(acl->ctx_prefix);
 696	for (i = 1; i <= strlen(acl->ctx_prefix); i++)
 697		oid->subs[sub + i] = acl->ctx_prefix[i - 1];
 698	sub += strlen(acl->ctx_prefix) + 1;
 699	oid->subs[sub++] = acl->sec_model;
 700	oid->subs[sub] = acl->sec_level;
 701}
 702
 703static int
 704vacm_access_rule_index_decode(const struct asn_oid *oid, uint sub, char *gname,
 705    char *cprefix, int32_t *smodel, int32_t *slevel)
 706{
 707	uint32_t i;
 708
 709	if (oid->subs[sub] >= SNMP_ADM_STR32_SIZ)
 710		return (-1);
 711
 712	for (i = 0; i < oid->subs[sub]; i++)
 713		gname[i] = oid->subs[sub + i + 1];
 714	gname[i] = '\0';
 715	sub += strlen(gname) + 1;
 716
 717	if (oid->subs[sub] >= SNMP_ADM_STR32_SIZ)
 718		return (-1);
 719
 720	for (i = 0; i < oid->subs[sub]; i++)
 721		cprefix[i] = oid->subs[sub + i + 1];
 722	cprefix[i] = '\0';
 723	sub += strlen(cprefix) + 1;
 724
 725	*smodel = oid->subs[sub++];
 726	*slevel = oid->subs[sub];
 727
 728	return (0);
 729}
 730
 731struct vacm_access *
 732vacm_get_access_rule(const struct asn_oid *oid, uint sub)
 733{
 734	int32_t smodel, slevel;
 735	char gname[SNMP_ADM_STR32_SIZ], prefix[SNMP_ADM_STR32_SIZ];
 736	struct vacm_access *acl;
 737
 738	if (vacm_access_rule_index_decode(oid, sub, gname, prefix, &smodel,
 739	    &slevel) < 0)
 740		return (NULL);
 741
 742	for (acl = vacm_first_access_rule(); acl != NULL;
 743	    acl = vacm_next_access_rule(acl))
 744		if (strcmp(gname, acl->group->groupname) == 0 &&
 745		    strcmp(prefix, acl->ctx_prefix) == 0 &&
 746		    smodel == acl->sec_model && slevel == acl->sec_level)
 747			return (acl);
 748
 749	return (NULL);
 750}
 751
 752struct vacm_access *
 753vacm_get_next_access_rule(const struct asn_oid *oid __unused, uint sub __unused)
 754{
 755	int32_t smodel, slevel;
 756	char gname[SNMP_ADM_STR32_SIZ], prefix[SNMP_ADM_STR32_SIZ];
 757	struct vacm_access *acl;
 758
 759	if (oid->len - sub == 0)
 760		return (vacm_first_access_rule());
 761
 762	if (vacm_access_rule_index_decode(oid, sub, gname, prefix, &smodel,
 763	    &slevel) < 0)
 764		return (NULL);
 765
 766	for (acl = vacm_first_access_rule(); acl != NULL;
 767	    acl = vacm_next_access_rule(acl))
 768		if (strcmp(gname, acl->group->groupname) == 0 &&
 769		    strcmp(prefix, acl->ctx_prefix) == 0 &&
 770		    smodel == acl->sec_model && slevel == acl->sec_model)
 771			return (vacm_next_access_rule(acl));
 772
 773	return (NULL);
 774}
 775
 776static int
 777vacm_view_index_decode(const struct asn_oid *oid, uint sub, char *vname,
 778   struct asn_oid *view_oid)
 779{	
 780	uint32_t i;
 781	int viod_off;
 782
 783	if (oid->subs[sub] >= SNMP_ADM_STR32_SIZ)
 784		return (-1);
 785
 786	for (i = 0; i < oid->subs[sub]; i++)
 787		vname[i] = oid->subs[sub + i + 1];
 788	vname[i] = '\0';
 789
 790	viod_off = sub + oid->subs[sub] + 1;
 791	if ((view_oid->len = oid->subs[viod_off]) > ASN_MAXOIDLEN)
 792		return (-1);
 793
 794	memcpy(&view_oid->subs[0], &oid->subs[viod_off + 1],
 795	    view_oid->len * sizeof(view_oid->subs[0]));
 796
 797	return (0);
 798}
 799
 800static void
 801vacm_append_viewindex(struct asn_oid *oid, uint sub, const struct vacm_view *view)
 802{
 803	uint32_t i;
 804
 805	oid->len = sub + strlen(view->viewname) + 1;
 806	oid->subs[sub] = strlen(view->viewname);
 807	for (i = 1; i <= strlen(view->viewname); i++)
 808		oid->subs[sub + i] = view->viewname[i - 1];
 809
 810	sub += strlen(view->viewname) + 1;
 811	oid->subs[sub] = view->subtree.len;
 812	oid->len++;
 813	asn_append_oid(oid, &view->subtree);
 814}
 815
 816struct vacm_view *
 817vacm_get_view(const struct asn_oid *oid, uint sub)
 818{
 819	char vname[SNMP_ADM_STR32_SIZ];
 820	struct asn_oid subtree;
 821	struct vacm_view *view;
 822
 823	if (vacm_view_index_decode(oid, sub, vname, &subtree) < 0)
 824		return (NULL);
 825
 826	for (view = vacm_first_view(); view != NULL; view = vacm_next_view(view))
 827		if (strcmp(vname, view->viewname) == 0 &&
 828		    asn_compare_oid(&subtree, &view->subtree)== 0)
 829			return (view);
 830
 831	return (NULL);
 832}
 833
 834struct vacm_view *
 835vacm_get_next_view(const struct asn_oid *oid, uint sub)
 836{
 837	char vname[SNMP_ADM_STR32_SIZ];
 838	struct asn_oid subtree;
 839	struct vacm_view *view;
 840
 841	if (oid->len - sub == 0)
 842		return (vacm_first_view());
 843
 844	if (vacm_view_index_decode(oid, sub, vname, &subtree) < 0)
 845		return (NULL);
 846
 847	for (view = vacm_first_view(); view != NULL; view = vacm_next_view(view))
 848		if (strcmp(vname, view->viewname) == 0 &&
 849		    asn_compare_oid(&subtree, &view->subtree)== 0)
 850			return (vacm_next_view(view));
 851
 852	return (NULL);
 853}
 854
 855static struct vacm_view *
 856vacm_get_view_by_name(u_char *octets, u_int len)
 857{
 858	struct vacm_view *view;
 859
 860	for (view = vacm_first_view(); view != NULL; view = vacm_next_view(view))
 861		if (strlen(view->viewname) == len &&
 862		    memcmp(octets, view->viewname, len) == 0)
 863			return (view);
 864
 865	return (NULL);
 866}
 867
 868static struct vacm_context *
 869vacm_get_context(const struct asn_oid *oid, uint sub)
 870{
 871	char cname[SNMP_ADM_STR32_SIZ];
 872	size_t cnamelen;
 873	u_int index_count;
 874	struct vacm_context *vacm_ctx;
 875
 876	if (oid->subs[sub] >= SNMP_ADM_STR32_SIZ)
 877		return (NULL);
 878
 879	index_count = 0;
 880	index_count = SNMP_INDEX(index_count, 1);
 881	if (index_decode(oid, sub, index_count, &cname, &cnamelen))
 882		return (NULL);
 883
 884	for (vacm_ctx = vacm_first_context(); vacm_ctx != NULL;
 885	    vacm_ctx = vacm_next_context(vacm_ctx))
 886		if (strcmp(cname, vacm_ctx->ctxname) == 0)
 887			return (vacm_ctx);
 888
 889	return (NULL);
 890}
 891
 892static struct vacm_context *
 893vacm_get_next_context(const struct asn_oid *oid, uint sub)
 894{
 895	char cname[SNMP_ADM_STR32_SIZ];
 896	size_t cnamelen;
 897	u_int index_count;
 898	struct vacm_context *vacm_ctx;
 899
 900	if (oid->len - sub == 0)
 901		return (vacm_first_context());
 902
 903	if (oid->subs[sub] >= SNMP_ADM_STR32_SIZ)
 904		return (NULL);
 905
 906	index_count = 0;
 907	index_count = SNMP_INDEX(index_count, 1);
 908	if (index_decode(oid, sub, index_count, &cname, &cnamelen))
 909		return (NULL);
 910
 911	for (vacm_ctx = vacm_first_context(); vacm_ctx != NULL;
 912	    vacm_ctx = vacm_next_context(vacm_ctx))
 913		if (strcmp(cname, vacm_ctx->ctxname) == 0)
 914			return (vacm_next_context(vacm_ctx));
 915
 916	return (NULL);
 917}
 918
 919static void
 920vacm_append_ctxindex(struct asn_oid *oid, uint sub,
 921    const struct vacm_context *ctx)
 922{
 923	uint32_t i;
 924
 925	oid->len = sub + strlen(ctx->ctxname) + 1;
 926	oid->subs[sub] = strlen(ctx->ctxname);
 927	for (i = 1; i <= strlen(ctx->ctxname); i++)
 928		oid->subs[sub + i] = ctx->ctxname[i - 1];
 929}
 930
 931/*
 932 * VACM snmp module initialization hook.
 933 * Returns 0 on success, < 0 on error.
 934 */
 935static int
 936vacm_init(struct lmodule *mod, int argc __unused, char *argv[] __unused)
 937{
 938	vacm_module = mod;
 939	vacm_lock = random();
 940	vacm_groups_init();
 941
 942	/* XXX: TODO - initialize structures */
 943	return (0);
 944}
 945
 946/*
 947 * VACM snmp module finalization hook.
 948 */
 949static int
 950vacm_fini(void)
 951{
 952	/* XXX: TODO - cleanup */
 953	vacm_flush_contexts(reg_vacm);
 954	or_unregister(reg_vacm);
 955
 956	return (0);
 957}
 958
 959/*
 960 * VACM snmp module start operation.
 961 */
 962static void
 963vacm_start(void)
 964{
 965	static char dflt_ctx[] = "";
 966
 967	reg_vacm = or_register(&oid_vacm,
 968	    "The MIB module for managing SNMP View-based Access Control Model.",
 969	    vacm_module);
 970
 971	(void)vacm_add_context(dflt_ctx, reg_vacm);
 972}
 973
 974static void
 975vacm_dump(void)
 976{
 977	struct vacm_context *vacmctx;
 978	struct vacm_user *vuser;
 979	struct vacm_access *vacl;
 980	struct vacm_view *view;
 981	static char oidbuf[ASN_OIDSTRLEN];
 982
 983	syslog(LOG_ERR, "\n");
 984	syslog(LOG_ERR, "Context list:");
 985	for (vacmctx = vacm_first_context(); vacmctx != NULL;
 986	    vacmctx = vacm_next_context(vacmctx))
 987		syslog(LOG_ERR, "Context \"%s\", module id %d",
 988		    vacmctx->ctxname, vacmctx->regid);
 989
 990	syslog(LOG_ERR, "VACM users:");
 991	for (vuser = vacm_first_user(); vuser != NULL;
 992	    vuser = vacm_next_user(vuser))
 993		syslog(LOG_ERR, "Uname %s, Group %s, model %d", vuser->secname,
 994		    vuser->group!= NULL?vuser->group->groupname:"Unknown",
 995		    vuser->sec_model);
 996
 997	syslog(LOG_ERR, "VACM Access rules:");
 998	for (vacl = vacm_first_access_rule(); vacl != NULL;
 999	    vacl = vacm_next_access_rule(vacl))
1000		syslog(LOG_ERR, "Group %s, CtxPrefix %s, Model %d, Level %d, "
1001		    "RV %s, WR %s, NV %s", vacl->group!=NULL?
1002		    vacl->group->groupname:"Unknown", vacl->ctx_prefix,
1003		    vacl->sec_model, vacl->sec_level, vacl->read_view!=NULL?
1004		    vacl->read_view->viewname:"None", vacl->write_view!=NULL?
1005		    vacl->write_view->viewname:"None", vacl->notify_view!=NULL?
1006		    vacl->notify_view->viewname:"None");
1007
1008	syslog(LOG_ERR, "VACM Views:");
1009	for (view = vacm_first_view(); view != NULL; view = vacm_next_view(view))
1010		syslog(LOG_ERR, "View %s, Tree %s - %s", view->viewname,
1011		    asn_oid2str_r(&view->subtree, oidbuf), view->exclude?
1012		    "excluded":"included");
1013}
1014
1015const char vacm_comment[] = \
1016"This module implements SNMP View-based Access Control Model defined in RFC 3415.";
1017
1018const struct snmp_module config = {
1019	.comment =	vacm_comment,
1020	.init =		vacm_init,
1021	.fini =		vacm_fini,
1022	.start =	vacm_start,
1023	.tree =		vacm_ctree,
1024	.dump =		vacm_dump,
1025	.tree_size =	vacm_CTREE_SIZE,
1026};