1216294Ssyrinx/*-
2216294Ssyrinx * Copyright (c) 2010 The FreeBSD Foundation
3216294Ssyrinx * All rights reserved.
4216294Ssyrinx *
5216294Ssyrinx * This software was developed by Shteryana Sotirova Shopova under
6216294Ssyrinx * sponsorship from the FreeBSD Foundation.
7216294Ssyrinx *
8216294Ssyrinx * Redistribution and use in source and binary forms, with or without
9216294Ssyrinx * modification, are permitted provided that the following conditions
10216294Ssyrinx * are met:
11216294Ssyrinx * 1. Redistributions of source code must retain the above copyright
12216294Ssyrinx *    notice, this list of conditions and the following disclaimer.
13216294Ssyrinx * 2. Redistributions in binary form must reproduce the above copyright
14216294Ssyrinx *    notice, this list of conditions and the following disclaimer in the
15216294Ssyrinx *    documentation and/or other materials provided with the distribution.
16216294Ssyrinx *
17216294Ssyrinx * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18216294Ssyrinx * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19216294Ssyrinx * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20216294Ssyrinx * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21216294Ssyrinx * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22216294Ssyrinx * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23216294Ssyrinx * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24216294Ssyrinx * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25216294Ssyrinx * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26216294Ssyrinx * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27216294Ssyrinx * SUCH DAMAGE.
28216294Ssyrinx *
29216294Ssyrinx * $FreeBSD$
30216294Ssyrinx */
31216294Ssyrinx#include <sys/queue.h>
32216294Ssyrinx#include <sys/types.h>
33216294Ssyrinx
34216294Ssyrinx#include <errno.h>
35216294Ssyrinx#include <stdarg.h>
36216294Ssyrinx#include <stdlib.h>
37216294Ssyrinx#include <stdio.h>
38216294Ssyrinx#include <stdint.h>
39216294Ssyrinx#include <string.h>
40216294Ssyrinx#include <syslog.h>
41216294Ssyrinx
42216294Ssyrinx#include "asn1.h"
43216294Ssyrinx#include "snmp.h"
44216294Ssyrinx#include "snmpmod.h"
45216294Ssyrinx
46216294Ssyrinx#include "vacm_tree.h"
47216294Ssyrinx#include "vacm_oid.h"
48216294Ssyrinx
49216294Ssyrinxstatic struct lmodule *vacm_module;
50216294Ssyrinx/* For the registration. */
51216294Ssyrinxstatic const struct asn_oid oid_vacm = OIDX_snmpVacmMIB;
52216294Ssyrinx
53216294Ssyrinxstatic uint reg_vacm;
54216294Ssyrinx
55216294Ssyrinxstatic int32_t vacm_lock;
56216294Ssyrinx
57216294Ssyrinx/*
58216294Ssyrinx * Internal datastructures and forward declarations.
59216294Ssyrinx */
60216294Ssyrinxstatic void		vacm_append_userindex(struct asn_oid *,
61216294Ssyrinx    uint, const struct vacm_user *);
62216294Ssyrinxstatic int		vacm_user_index_decode(const struct asn_oid *,
63216294Ssyrinx    uint, int32_t *, char *);
64216294Ssyrinxstatic struct vacm_user *vacm_get_user(const struct asn_oid *,
65216294Ssyrinx    uint);
66216294Ssyrinxstatic struct vacm_user *vacm_get_next_user(const struct asn_oid *,
67216294Ssyrinx    uint);
68216294Ssyrinxstatic void		vacm_append_access_rule_index(struct asn_oid *,
69216294Ssyrinx    uint, const struct vacm_access *);
70216294Ssyrinxstatic int		vacm_access_rule_index_decode(const struct asn_oid *,
71216294Ssyrinx    uint, char *, char *, int32_t *, int32_t *);
72216294Ssyrinxstatic struct vacm_access *	vacm_get_access_rule(const struct asn_oid *,
73216294Ssyrinx    uint);
74216294Ssyrinxstatic struct vacm_access *	vacm_get_next_access_rule(const struct asn_oid *,
75216294Ssyrinx    uint);
76216294Ssyrinxstatic int		vacm_view_index_decode(const struct asn_oid *, uint,
77216294Ssyrinx    char *, struct asn_oid *);
78216294Ssyrinxstatic void		vacm_append_viewindex(struct asn_oid *, uint,
79216294Ssyrinx    const struct vacm_view *);
80216294Ssyrinxstatic struct vacm_view	*vacm_get_view(const struct asn_oid *, uint);
81216294Ssyrinxstatic struct vacm_view	*vacm_get_next_view(const struct asn_oid *, uint);
82216294Ssyrinxstatic struct vacm_view *vacm_get_view_by_name(u_char *, u_int);
83216294Ssyrinxstatic struct vacm_context	*vacm_get_context(const struct asn_oid *, uint);
84216294Ssyrinxstatic struct vacm_context	*vacm_get_next_context(const struct asn_oid *,
85216294Ssyrinx    uint);
86216294Ssyrinxstatic void			vacm_append_ctxindex(struct asn_oid *, uint,
87216294Ssyrinx    const struct vacm_context *);
88216294Ssyrinx
89216294Ssyrinxint
90216294Ssyrinxop_vacm_context(struct snmp_context *ctx __unused, struct snmp_value *val,
91216294Ssyrinx    uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
92216294Ssyrinx{
93216294Ssyrinx	char cname[SNMP_ADM_STR32_SIZ];
94216294Ssyrinx	size_t cnamelen;
95216294Ssyrinx	struct vacm_context *vacm_ctx;
96216294Ssyrinx
97216294Ssyrinx	if (val->var.subs[sub - 1] != LEAF_vacmContextName)
98216294Ssyrinx		abort();
99216294Ssyrinx
100216294Ssyrinx	switch (op) {
101216294Ssyrinx	case SNMP_OP_GET:
102216294Ssyrinx		if ((vacm_ctx = vacm_get_context(&val->var, sub)) == NULL)
103216294Ssyrinx			return (SNMP_ERR_NOSUCHNAME);
104216294Ssyrinx		break;
105216294Ssyrinx
106216294Ssyrinx	case SNMP_OP_GETNEXT:
107216294Ssyrinx		if ((vacm_ctx = vacm_get_next_context(&val->var, sub)) == NULL)
108216294Ssyrinx			return (SNMP_ERR_NOSUCHNAME);
109216294Ssyrinx		vacm_append_ctxindex(&val->var, sub, vacm_ctx);
110216294Ssyrinx		break;
111216294Ssyrinx
112216294Ssyrinx	case SNMP_OP_SET:
113216294Ssyrinx		if ((vacm_ctx = vacm_get_context(&val->var, sub)) != NULL)
114216294Ssyrinx			return (SNMP_ERR_WRONG_VALUE);
115216294Ssyrinx		if (community != COMM_INITIALIZE)
116216294Ssyrinx			return (SNMP_ERR_NOT_WRITEABLE);
117216294Ssyrinx		if (val->var.subs[sub] >= SNMP_ADM_STR32_SIZ)
118216294Ssyrinx			return (SNMP_ERR_WRONG_VALUE);
119216294Ssyrinx		if (index_decode(&val->var, sub, iidx, &cname, &cnamelen))
120216294Ssyrinx			return (SNMP_ERR_GENERR);
121216294Ssyrinx		cname[cnamelen] = '\0';
122216294Ssyrinx		if ((vacm_ctx = vacm_add_context(cname, reg_vacm)) == NULL)
123216294Ssyrinx			return (SNMP_ERR_GENERR);
124216294Ssyrinx		return (SNMP_ERR_NOERROR);
125216294Ssyrinx
126216294Ssyrinx	case SNMP_OP_COMMIT:
127216294Ssyrinx		/* FALLTHROUGH*/
128216294Ssyrinx	case SNMP_OP_ROLLBACK:
129216294Ssyrinx		return (SNMP_ERR_NOERROR);
130216294Ssyrinx	default:
131216294Ssyrinx		abort();
132216294Ssyrinx	}
133216294Ssyrinx
134216294Ssyrinx	return (string_get(val, vacm_ctx->ctxname, -1));
135216294Ssyrinx}
136216294Ssyrinx
137216294Ssyrinxint
138216294Ssyrinxop_vacm_security_to_group(struct snmp_context *ctx, struct snmp_value *val,
139216294Ssyrinx    uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
140216294Ssyrinx{
141216294Ssyrinx	int32_t smodel;
142216294Ssyrinx	char uname[SNMP_ADM_STR32_SIZ];
143216294Ssyrinx	struct vacm_user *user;
144216294Ssyrinx
145216294Ssyrinx	switch (op) {
146216294Ssyrinx	case SNMP_OP_GET:
147216294Ssyrinx		if ((user = vacm_get_user(&val->var, sub)) == NULL)
148216294Ssyrinx			return (SNMP_ERR_NOSUCHNAME);
149216294Ssyrinx		break;
150216294Ssyrinx
151216294Ssyrinx	case SNMP_OP_GETNEXT:
152216294Ssyrinx		if ((user = vacm_get_next_user(&val->var, sub)) == NULL)
153216294Ssyrinx			return (SNMP_ERR_NOSUCHNAME);
154216294Ssyrinx		vacm_append_userindex(&val->var, sub, user);
155216294Ssyrinx		break;
156216294Ssyrinx
157216294Ssyrinx	case SNMP_OP_SET:
158216294Ssyrinx		if ((user = vacm_get_user(&val->var, sub)) == NULL &&
159216294Ssyrinx		    val->var.subs[sub - 1] != LEAF_vacmSecurityToGroupStatus)
160216294Ssyrinx			return (SNMP_ERR_NOSUCHNAME);
161216294Ssyrinx
162216294Ssyrinx		if (user != NULL) {
163216294Ssyrinx			if (community != COMM_INITIALIZE &&
164216294Ssyrinx			    user->type == StorageType_readOnly)
165216294Ssyrinx				return (SNMP_ERR_NOT_WRITEABLE);
166216294Ssyrinx			if (user->status == RowStatus_active &&
167216294Ssyrinx			    val->v.integer != RowStatus_destroy)
168216294Ssyrinx				return (SNMP_ERR_INCONS_VALUE);
169216294Ssyrinx		}
170216294Ssyrinx
171216294Ssyrinx		switch (val->var.subs[sub - 1]) {
172216294Ssyrinx		case LEAF_vacmGroupName:
173216294Ssyrinx			ctx->scratch->ptr1 = user->group->groupname;
174216294Ssyrinx			ctx->scratch->int1 = strlen(user->group->groupname);
175216294Ssyrinx			return (vacm_user_set_group(user,
176216294Ssyrinx			    val->v.octetstring.octets,val->v.octetstring.len));
177216294Ssyrinx
178216294Ssyrinx		case LEAF_vacmSecurityToGroupStorageType:
179216294Ssyrinx			return (SNMP_ERR_INCONS_VALUE);
180216294Ssyrinx
181216294Ssyrinx		case LEAF_vacmSecurityToGroupStatus:
182216294Ssyrinx			if (user == NULL) {
183216294Ssyrinx				if (val->v.integer != RowStatus_createAndGo ||
184216294Ssyrinx				    vacm_user_index_decode(&val->var, sub,
185216294Ssyrinx				    &smodel, uname) < 0)
186216294Ssyrinx					return (SNMP_ERR_INCONS_VALUE);
187216294Ssyrinx				user = vacm_new_user(smodel, uname);
188216294Ssyrinx				if (user == NULL)
189216294Ssyrinx					return (SNMP_ERR_GENERR);
190216294Ssyrinx				user->status = RowStatus_destroy;
191216294Ssyrinx				if (community != COMM_INITIALIZE)
192216294Ssyrinx					user->type = StorageType_volatile;
193216294Ssyrinx				else
194216294Ssyrinx					user->type = StorageType_readOnly;
195216294Ssyrinx			} else if (val->v.integer != RowStatus_active &&
196216294Ssyrinx			    val->v.integer != RowStatus_destroy)
197216294Ssyrinx				return (SNMP_ERR_INCONS_VALUE);
198216294Ssyrinx			ctx->scratch->int1 = user->status;
199216294Ssyrinx			user->status = val->v.integer;
200216294Ssyrinx			break;
201216294Ssyrinx		}
202216294Ssyrinx		return (SNMP_ERR_NOERROR);
203216294Ssyrinx
204216294Ssyrinx	case SNMP_OP_COMMIT:
205216294Ssyrinx		if (val->var.subs[sub - 1] != LEAF_vacmSecurityToGroupStatus)
206216294Ssyrinx			return (SNMP_ERR_NOERROR);
207216294Ssyrinx		if ((user = vacm_get_user(&val->var, sub)) == NULL)
208216294Ssyrinx			return (SNMP_ERR_GENERR);
209216294Ssyrinx		switch (val->v.integer) {
210216294Ssyrinx		case  RowStatus_destroy:
211216294Ssyrinx			return (vacm_delete_user(user));
212216294Ssyrinx
213216294Ssyrinx		case RowStatus_createAndGo:
214216294Ssyrinx			user->status = RowStatus_active;
215216294Ssyrinx			break;
216216294Ssyrinx
217216294Ssyrinx		default:
218216294Ssyrinx			break;
219216294Ssyrinx		}
220216294Ssyrinx		return (SNMP_ERR_NOERROR);
221216294Ssyrinx
222216294Ssyrinx	case SNMP_OP_ROLLBACK:
223216294Ssyrinx		if ((user = vacm_get_user(&val->var, sub)) == NULL)
224216294Ssyrinx			return (SNMP_ERR_GENERR);
225216294Ssyrinx		switch (val->var.subs[sub - 1]) {
226216294Ssyrinx		case LEAF_vacmGroupName:
227216294Ssyrinx			return (vacm_user_set_group(user, ctx->scratch->ptr1,
228216294Ssyrinx			    ctx->scratch->int1));
229216294Ssyrinx
230216294Ssyrinx		case LEAF_vacmSecurityToGroupStatus:
231216294Ssyrinx			if (ctx->scratch->int1 == RowStatus_destroy)
232216294Ssyrinx				return (vacm_delete_user(user));
233216294Ssyrinx			user->status = ctx->scratch->int1;
234216294Ssyrinx			break;
235216294Ssyrinx
236216294Ssyrinx		default:
237216294Ssyrinx			break;
238216294Ssyrinx		}
239216294Ssyrinx		return (SNMP_ERR_NOERROR);
240216294Ssyrinx
241216294Ssyrinx	default:
242216294Ssyrinx		abort();
243216294Ssyrinx	}
244216294Ssyrinx
245216294Ssyrinx	switch (val->var.subs[sub - 1]) {
246216294Ssyrinx	case LEAF_vacmGroupName:
247216294Ssyrinx		return (string_get(val, user->group->groupname, -1));
248216294Ssyrinx	case LEAF_vacmSecurityToGroupStorageType:
249216294Ssyrinx		val->v.integer = user->type;
250216294Ssyrinx		break;
251216294Ssyrinx	case LEAF_vacmSecurityToGroupStatus:
252216294Ssyrinx		val->v.integer = user->status;
253216294Ssyrinx		break;
254216294Ssyrinx	default:
255216294Ssyrinx		abort();
256216294Ssyrinx	}
257216294Ssyrinx
258216294Ssyrinx	return (SNMP_ERR_NOERROR);
259216294Ssyrinx}
260216294Ssyrinx
261216294Ssyrinxint
262216294Ssyrinxop_vacm_access(struct snmp_context *ctx, struct snmp_value *val, uint32_t sub,
263216294Ssyrinx    uint32_t iidx __unused, enum snmp_op op)
264216294Ssyrinx{
265216294Ssyrinx	int32_t smodel, slevel;
266216294Ssyrinx	char gname[SNMP_ADM_STR32_SIZ], cprefix[SNMP_ADM_STR32_SIZ];
267216294Ssyrinx	struct vacm_access *acl;
268216294Ssyrinx
269216294Ssyrinx	switch (op) {
270216294Ssyrinx	case SNMP_OP_GET:
271216294Ssyrinx		if ((acl = vacm_get_access_rule(&val->var, sub)) == NULL)
272216294Ssyrinx			return (SNMP_ERR_NOSUCHNAME);
273216294Ssyrinx		break;
274216294Ssyrinx
275216294Ssyrinx	case SNMP_OP_GETNEXT:
276216294Ssyrinx		if ((acl = vacm_get_next_access_rule(&val->var, sub)) == NULL)
277216294Ssyrinx			return (SNMP_ERR_NOSUCHNAME);
278216294Ssyrinx		vacm_append_access_rule_index(&val->var, sub, acl);
279216294Ssyrinx		break;
280216294Ssyrinx
281216294Ssyrinx	case SNMP_OP_SET:
282216294Ssyrinx		if ((acl = vacm_get_access_rule(&val->var, sub)) == NULL &&
283216294Ssyrinx		    val->var.subs[sub - 1] != LEAF_vacmAccessStatus)
284216294Ssyrinx				return (SNMP_ERR_NOSUCHNAME);
285216294Ssyrinx		if (acl != NULL && community != COMM_INITIALIZE &&
286216294Ssyrinx		    acl->type == StorageType_readOnly)
287216294Ssyrinx			return (SNMP_ERR_NOT_WRITEABLE);
288216294Ssyrinx
289216294Ssyrinx		switch (val->var.subs[sub - 1]) {
290216294Ssyrinx		case LEAF_vacmAccessContextMatch:
291216294Ssyrinx			ctx->scratch->int1 = acl->ctx_match;
292216294Ssyrinx			if (val->v.integer == vacmAccessContextMatch_exact)
293216294Ssyrinx				acl->ctx_match = 1;
294216294Ssyrinx			else if (val->v.integer == vacmAccessContextMatch_prefix)
295216294Ssyrinx				acl->ctx_match = 0;
296216294Ssyrinx			else
297216294Ssyrinx				return (SNMP_ERR_WRONG_VALUE);
298216294Ssyrinx			break;
299216294Ssyrinx
300216294Ssyrinx		case LEAF_vacmAccessReadViewName:
301216294Ssyrinx			ctx->scratch->ptr1 = acl->read_view;
302216294Ssyrinx			acl->read_view = vacm_get_view_by_name(val->v.octetstring.octets, val->v.octetstring.len);
303216294Ssyrinx			if (acl->read_view == NULL) {
304216294Ssyrinx				acl->read_view = ctx->scratch->ptr1;
305216294Ssyrinx				return (SNMP_ERR_INCONS_VALUE);
306216294Ssyrinx			}
307216294Ssyrinx			return (SNMP_ERR_NOERROR);
308216294Ssyrinx
309216294Ssyrinx		case LEAF_vacmAccessWriteViewName:
310216294Ssyrinx			ctx->scratch->ptr1 = acl->write_view;
311216294Ssyrinx			if ((acl->write_view =
312216294Ssyrinx			    vacm_get_view_by_name(val->v.octetstring.octets,
313216294Ssyrinx			    val->v.octetstring.len)) == NULL) {
314216294Ssyrinx				acl->write_view = ctx->scratch->ptr1;
315216294Ssyrinx				return (SNMP_ERR_INCONS_VALUE);
316216294Ssyrinx			}
317216294Ssyrinx			break;
318216294Ssyrinx
319216294Ssyrinx		case LEAF_vacmAccessNotifyViewName:
320216294Ssyrinx			ctx->scratch->ptr1 = acl->notify_view;
321216294Ssyrinx			if ((acl->notify_view =
322216294Ssyrinx			    vacm_get_view_by_name(val->v.octetstring.octets,
323216294Ssyrinx			    val->v.octetstring.len)) == NULL) {
324216294Ssyrinx				acl->notify_view = ctx->scratch->ptr1;
325216294Ssyrinx				return (SNMP_ERR_INCONS_VALUE);
326216294Ssyrinx			}
327216294Ssyrinx			break;
328216294Ssyrinx
329216294Ssyrinx		case LEAF_vacmAccessStorageType:
330216294Ssyrinx			return (SNMP_ERR_INCONS_VALUE);
331216294Ssyrinx
332216294Ssyrinx		case LEAF_vacmAccessStatus:
333216294Ssyrinx			if (acl == NULL) {
334216294Ssyrinx				if (val->v.integer != RowStatus_createAndGo ||
335216294Ssyrinx				    vacm_access_rule_index_decode(&val->var,
336216294Ssyrinx				    sub, gname, cprefix, &smodel, &slevel) < 0)
337216294Ssyrinx					return (SNMP_ERR_INCONS_VALUE);
338216294Ssyrinx				if ((acl = vacm_new_access_rule(gname, cprefix,
339216294Ssyrinx				    smodel, slevel)) == NULL)
340216294Ssyrinx					return (SNMP_ERR_GENERR);
341216294Ssyrinx				acl->status = RowStatus_destroy;
342216294Ssyrinx				if (community != COMM_INITIALIZE)
343216294Ssyrinx					acl->type = StorageType_volatile;
344216294Ssyrinx				else
345216294Ssyrinx					acl->type = StorageType_readOnly;
346216294Ssyrinx			} else if (val->v.integer != RowStatus_active &&
347216294Ssyrinx			    val->v.integer != RowStatus_destroy)
348216294Ssyrinx				return (SNMP_ERR_INCONS_VALUE);
349216294Ssyrinx			ctx->scratch->int1 = acl->status;
350216294Ssyrinx			acl->status = val->v.integer;
351216294Ssyrinx			break;
352216294Ssyrinx		}
353216294Ssyrinx		return (SNMP_ERR_NOERROR);
354216294Ssyrinx
355216294Ssyrinx	case SNMP_OP_COMMIT:
356216294Ssyrinx		if (val->var.subs[sub - 1] != LEAF_vacmAccessStatus)
357216294Ssyrinx			return (SNMP_ERR_NOERROR);
358216294Ssyrinx		if ((acl = vacm_get_access_rule(&val->var, sub)) == NULL)
359216294Ssyrinx			return (SNMP_ERR_GENERR);
360216294Ssyrinx		if (val->v.integer == RowStatus_destroy)
361216294Ssyrinx			return (vacm_delete_access_rule(acl));
362216294Ssyrinx		else
363216294Ssyrinx			acl->status = RowStatus_active;
364216294Ssyrinx		return (SNMP_ERR_NOERROR);
365216294Ssyrinx
366216294Ssyrinx	case SNMP_OP_ROLLBACK:
367216294Ssyrinx		if ((acl = vacm_get_access_rule(&val->var, sub)) == NULL)
368216294Ssyrinx			return (SNMP_ERR_GENERR);
369216294Ssyrinx		switch (val->var.subs[sub - 1]) {
370216294Ssyrinx		case LEAF_vacmAccessContextMatch:
371216294Ssyrinx			acl->ctx_match = ctx->scratch->int1;
372216294Ssyrinx			break;
373216294Ssyrinx		case LEAF_vacmAccessReadViewName:
374216294Ssyrinx			acl->read_view = ctx->scratch->ptr1;
375216294Ssyrinx			break;
376216294Ssyrinx		case LEAF_vacmAccessWriteViewName:
377216294Ssyrinx			acl->write_view = ctx->scratch->ptr1;
378216294Ssyrinx			break;
379216294Ssyrinx		case LEAF_vacmAccessNotifyViewName:
380216294Ssyrinx			acl->notify_view = ctx->scratch->ptr1;
381216294Ssyrinx			break;
382216294Ssyrinx		case LEAF_vacmAccessStatus:
383216294Ssyrinx			if (ctx->scratch->int1 == RowStatus_destroy)
384216294Ssyrinx				return (vacm_delete_access_rule(acl));
385216294Ssyrinx		default:
386216294Ssyrinx			break;
387216294Ssyrinx		}
388216294Ssyrinx		return (SNMP_ERR_NOERROR);
389216294Ssyrinx
390216294Ssyrinx	default:
391216294Ssyrinx		abort();
392216294Ssyrinx	}
393216294Ssyrinx
394216294Ssyrinx	switch (val->var.subs[sub - 1]) {
395216294Ssyrinx	case LEAF_vacmAccessContextMatch:
396216294Ssyrinx		return (string_get(val, acl->ctx_prefix, -1));
397216294Ssyrinx	case LEAF_vacmAccessReadViewName:
398216294Ssyrinx		if (acl->read_view != NULL)
399216294Ssyrinx			return (string_get(val, acl->read_view->viewname, -1));
400216294Ssyrinx		else
401216294Ssyrinx			return (string_get(val, NULL, 0));
402216294Ssyrinx	case LEAF_vacmAccessWriteViewName:
403216294Ssyrinx		if (acl->write_view != NULL)
404216294Ssyrinx			return (string_get(val, acl->write_view->viewname, -1));
405216294Ssyrinx		else
406216294Ssyrinx			return (string_get(val, NULL, 0));
407216294Ssyrinx	case LEAF_vacmAccessNotifyViewName:
408216294Ssyrinx		if (acl->notify_view != NULL)
409216294Ssyrinx			return (string_get(val, acl->notify_view->viewname, -1));
410216294Ssyrinx		else
411216294Ssyrinx			return (string_get(val, NULL, 0));
412216294Ssyrinx	case LEAF_vacmAccessStorageType:
413216294Ssyrinx		val->v.integer = acl->type;
414216294Ssyrinx		break;
415216294Ssyrinx	case LEAF_vacmAccessStatus:
416216294Ssyrinx		val->v.integer = acl->status;
417216294Ssyrinx		break;
418216294Ssyrinx	default:
419216294Ssyrinx		abort();
420216294Ssyrinx	}
421216294Ssyrinx
422216294Ssyrinx	return (SNMP_ERR_NOERROR);
423216294Ssyrinx}
424216294Ssyrinx
425216294Ssyrinxint
426216294Ssyrinxop_vacm_view_lock(struct snmp_context *ctx __unused, struct snmp_value *val,
427216294Ssyrinx    uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
428216294Ssyrinx{
429216294Ssyrinx	if (val->var.subs[sub - 1] != LEAF_vacmViewSpinLock)
430216294Ssyrinx		return (SNMP_ERR_NOSUCHNAME);
431216294Ssyrinx
432216294Ssyrinx	switch (op) {
433216294Ssyrinx	case SNMP_OP_GET:
434216294Ssyrinx		if (++vacm_lock == INT32_MAX)
435216294Ssyrinx			vacm_lock = 0;
436216294Ssyrinx		val->v.integer = vacm_lock;
437216294Ssyrinx		break;
438216294Ssyrinx
439216294Ssyrinx	case SNMP_OP_GETNEXT:
440216294Ssyrinx		abort();
441216294Ssyrinx
442216294Ssyrinx	case SNMP_OP_SET:
443216294Ssyrinx		if (val->v.integer != vacm_lock)
444216294Ssyrinx			return (SNMP_ERR_INCONS_VALUE);
445216294Ssyrinx		break;
446216294Ssyrinx
447216294Ssyrinx	case SNMP_OP_ROLLBACK:
448216294Ssyrinx		/* FALLTHROUGH */
449216294Ssyrinx	case SNMP_OP_COMMIT:
450216294Ssyrinx		break;
451216294Ssyrinx	}
452216294Ssyrinx
453216294Ssyrinx	return (SNMP_ERR_NOERROR);
454216294Ssyrinx}
455216294Ssyrinx
456216294Ssyrinxint
457216294Ssyrinxop_vacm_view(struct snmp_context *ctx, struct snmp_value *val, uint32_t sub,
458216294Ssyrinx    uint32_t iidx __unused, enum snmp_op op)
459216294Ssyrinx{
460216294Ssyrinx	char vname[SNMP_ADM_STR32_SIZ];
461216294Ssyrinx	struct asn_oid oid;
462216294Ssyrinx	struct vacm_view *view;
463216294Ssyrinx
464216294Ssyrinx	switch (op) {
465216294Ssyrinx	case SNMP_OP_GET:
466216294Ssyrinx		if ((view = vacm_get_view(&val->var, sub)) == NULL)
467216294Ssyrinx			return (SNMP_ERR_NOSUCHNAME);
468216294Ssyrinx		break;
469216294Ssyrinx
470216294Ssyrinx	case SNMP_OP_GETNEXT:
471216294Ssyrinx		if ((view = vacm_get_next_view(&val->var, sub)) == NULL)
472216294Ssyrinx			return (SNMP_ERR_NOSUCHNAME);
473216294Ssyrinx		vacm_append_viewindex(&val->var, sub, view);
474216294Ssyrinx		break;
475216294Ssyrinx
476216294Ssyrinx	case SNMP_OP_SET:
477216294Ssyrinx		if ((view = vacm_get_view(&val->var, sub)) == NULL &&
478216294Ssyrinx		    val->var.subs[sub - 1] != LEAF_vacmViewTreeFamilyStatus)
479216294Ssyrinx				return (SNMP_ERR_NOSUCHNAME);
480216294Ssyrinx
481216294Ssyrinx		if (view != NULL) {
482216294Ssyrinx			if (community != COMM_INITIALIZE &&
483216294Ssyrinx			    view->type == StorageType_readOnly)
484216294Ssyrinx				return (SNMP_ERR_NOT_WRITEABLE);
485216294Ssyrinx			if (view->status == RowStatus_active &&
486216294Ssyrinx			    val->v.integer != RowStatus_destroy)
487216294Ssyrinx				return (SNMP_ERR_INCONS_VALUE);
488216294Ssyrinx		}
489216294Ssyrinx
490216294Ssyrinx		switch (val->var.subs[sub - 1]) {
491216294Ssyrinx		case LEAF_vacmViewTreeFamilyMask:
492216294Ssyrinx			if (val->v.octetstring.len > sizeof(view->mask))
493216294Ssyrinx			ctx->scratch->ptr1 = malloc(sizeof(view->mask));
494216294Ssyrinx			if (ctx->scratch->ptr1 == NULL)
495216294Ssyrinx				return (SNMP_ERR_GENERR);
496216294Ssyrinx			memset(ctx->scratch->ptr1, 0, sizeof(view->mask));
497216294Ssyrinx			memcpy(ctx->scratch->ptr1, view->mask,
498216294Ssyrinx			    sizeof(view->mask));
499216294Ssyrinx			memset(view->mask, 0, sizeof(view->mask));
500216294Ssyrinx			memcpy(view->mask, val->v.octetstring.octets,
501216294Ssyrinx			    val->v.octetstring.len);
502216294Ssyrinx			break;
503216294Ssyrinx
504216294Ssyrinx		case LEAF_vacmViewTreeFamilyType:
505216294Ssyrinx			ctx->scratch->int1 = view->exclude;
506216294Ssyrinx			if (val->v.integer == vacmViewTreeFamilyType_included)
507216294Ssyrinx				view->exclude = 0;
508216294Ssyrinx			else if (val->v.integer == vacmViewTreeFamilyType_excluded)
509216294Ssyrinx				view->exclude = 1;
510216294Ssyrinx			else
511216294Ssyrinx				return (SNMP_ERR_WRONG_VALUE);
512216294Ssyrinx			break;
513216294Ssyrinx
514216294Ssyrinx		case LEAF_vacmViewTreeFamilyStorageType:
515216294Ssyrinx			return (SNMP_ERR_INCONS_VALUE);
516216294Ssyrinx
517216294Ssyrinx		case LEAF_vacmViewTreeFamilyStatus:
518216294Ssyrinx			if (view == NULL) {
519216294Ssyrinx				if (val->v.integer != RowStatus_createAndGo ||
520216294Ssyrinx				    vacm_view_index_decode(&val->var, sub, vname,
521216294Ssyrinx				    &oid) < 0)
522216294Ssyrinx					return (SNMP_ERR_INCONS_VALUE);
523216294Ssyrinx				if ((view = vacm_new_view(vname, &oid)) == NULL)
524216294Ssyrinx					return (SNMP_ERR_GENERR);
525216294Ssyrinx				view->status = RowStatus_destroy;
526216294Ssyrinx				if (community != COMM_INITIALIZE)
527216294Ssyrinx					view->type = StorageType_volatile;
528216294Ssyrinx				else
529216294Ssyrinx					view->type = StorageType_readOnly;
530216294Ssyrinx			} else if (val->v.integer != RowStatus_active &&
531216294Ssyrinx			    val->v.integer != RowStatus_destroy)
532216294Ssyrinx				return (SNMP_ERR_INCONS_VALUE);
533216294Ssyrinx			ctx->scratch->int1 = view->status;
534216294Ssyrinx			view->status = val->v.integer;
535216294Ssyrinx			break;
536216294Ssyrinx		}
537216294Ssyrinx		return (SNMP_ERR_NOERROR);
538216294Ssyrinx
539216294Ssyrinx	case SNMP_OP_COMMIT:
540216294Ssyrinx		switch (val->var.subs[sub - 1]) {
541216294Ssyrinx		case LEAF_vacmViewTreeFamilyMask:
542216294Ssyrinx			free(ctx->scratch->ptr1);
543216294Ssyrinx			break;
544216294Ssyrinx		case LEAF_vacmViewTreeFamilyStatus:
545216294Ssyrinx			if ((view = vacm_get_view(&val->var, sub)) == NULL)
546216294Ssyrinx				return (SNMP_ERR_GENERR);
547216294Ssyrinx			switch (val->v.integer) {
548216294Ssyrinx			case  RowStatus_destroy:
549216294Ssyrinx				return (vacm_delete_view(view));
550216294Ssyrinx
551216294Ssyrinx			case RowStatus_createAndGo:
552216294Ssyrinx				view->status = RowStatus_active;
553216294Ssyrinx				break;
554216294Ssyrinx
555216294Ssyrinx			default:
556216294Ssyrinx				/* NOTREACHED*/
557216294Ssyrinx				return (SNMP_ERR_GENERR);
558216294Ssyrinx			}
559216294Ssyrinx		default:
560216294Ssyrinx			break;
561216294Ssyrinx		}
562216294Ssyrinx		return (SNMP_ERR_NOERROR);
563216294Ssyrinx
564216294Ssyrinx	case SNMP_OP_ROLLBACK:
565216294Ssyrinx		if ((view = vacm_get_view(&val->var, sub)) == NULL)
566216294Ssyrinx			return (SNMP_ERR_GENERR);
567216294Ssyrinx		switch (val->var.subs[sub - 1]) {
568216294Ssyrinx		case LEAF_vacmViewTreeFamilyMask:
569216294Ssyrinx			memcpy(view->mask, ctx->scratch->ptr1,
570216294Ssyrinx			    sizeof(view->mask));
571216294Ssyrinx			free(ctx->scratch->ptr1);
572216294Ssyrinx			break;
573216294Ssyrinx		case LEAF_vacmViewTreeFamilyType:
574216294Ssyrinx			view->exclude = ctx->scratch->int1;
575216294Ssyrinx			break;
576216294Ssyrinx		case LEAF_vacmViewTreeFamilyStatus:
577216294Ssyrinx			if (ctx->scratch->int1 == RowStatus_destroy)
578216294Ssyrinx				return (vacm_delete_view(view));
579216294Ssyrinx			break;
580216294Ssyrinx		default:
581216294Ssyrinx			break;
582216294Ssyrinx		}
583216294Ssyrinx		return (SNMP_ERR_NOERROR);
584216294Ssyrinx
585216294Ssyrinx	default:
586216294Ssyrinx		abort();
587216294Ssyrinx	}
588216294Ssyrinx
589216294Ssyrinx	switch (val->var.subs[sub - 1]) {
590216294Ssyrinx	case LEAF_vacmViewTreeFamilyMask:
591216294Ssyrinx		return (string_get(val, view->mask, sizeof(view->mask)));
592216294Ssyrinx	case LEAF_vacmViewTreeFamilyType:
593216294Ssyrinx		if (view->exclude)
594216294Ssyrinx			val->v.integer = vacmViewTreeFamilyType_excluded;
595216294Ssyrinx		else
596216294Ssyrinx			val->v.integer = vacmViewTreeFamilyType_included;
597216294Ssyrinx		break;
598216294Ssyrinx	case LEAF_vacmViewTreeFamilyStorageType:
599216294Ssyrinx		val->v.integer = view->type;
600216294Ssyrinx		break;
601216294Ssyrinx	case LEAF_vacmViewTreeFamilyStatus:
602216294Ssyrinx		val->v.integer = view->status;
603216294Ssyrinx		break;
604216294Ssyrinx	default:
605216294Ssyrinx		abort();
606216294Ssyrinx	}
607216294Ssyrinx
608216294Ssyrinx	return (SNMP_ERR_NOERROR);
609216294Ssyrinx}
610216294Ssyrinx
611216294Ssyrinxstatic void
612216294Ssyrinxvacm_append_userindex(struct asn_oid *oid, uint sub,
613216294Ssyrinx    const struct vacm_user *user)
614216294Ssyrinx{
615216294Ssyrinx	uint32_t i;
616216294Ssyrinx
617216294Ssyrinx	oid->len = sub + strlen(user->secname) + 2;
618216294Ssyrinx	oid->subs[sub++] = user->sec_model;
619216294Ssyrinx	oid->subs[sub] = strlen(user->secname);
620216294Ssyrinx	for (i = 1; i <= strlen(user->secname); i++)
621216294Ssyrinx		oid->subs[sub + i] = user->secname[i - 1];
622216294Ssyrinx}
623216294Ssyrinx
624216294Ssyrinxstatic int
625216294Ssyrinxvacm_user_index_decode(const struct asn_oid *oid, uint sub,
626216294Ssyrinx    int32_t *smodel, char *uname)
627216294Ssyrinx{
628216294Ssyrinx	uint32_t i;
629216294Ssyrinx
630216294Ssyrinx	*smodel = oid->subs[sub++];
631216294Ssyrinx
632216294Ssyrinx	if (oid->subs[sub] >= SNMP_ADM_STR32_SIZ)
633216294Ssyrinx		return (-1);
634216294Ssyrinx
635216294Ssyrinx	for (i = 0; i < oid->subs[sub]; i++)
636216294Ssyrinx		uname[i] = oid->subs[sub + i + 1];
637216294Ssyrinx	uname[i] = '\0';
638216294Ssyrinx
639216294Ssyrinx	return (0);
640216294Ssyrinx}
641216294Ssyrinx
642216294Ssyrinxstatic struct vacm_user *
643216294Ssyrinxvacm_get_user(const struct asn_oid *oid, uint sub)
644216294Ssyrinx{
645216294Ssyrinx	int32_t smodel;
646216294Ssyrinx	char uname[SNMP_ADM_STR32_SIZ];
647216294Ssyrinx	struct vacm_user *user;
648216294Ssyrinx
649216294Ssyrinx	if (vacm_user_index_decode(oid, sub, &smodel, uname) < 0)
650216294Ssyrinx		return (NULL);
651216294Ssyrinx
652216294Ssyrinx	for (user = vacm_first_user(); user != NULL; user = vacm_next_user(user))
653216294Ssyrinx		if (strcmp(uname, user->secname) == 0 &&
654216294Ssyrinx		    user->sec_model == smodel)
655216294Ssyrinx			return (user);
656216294Ssyrinx
657216294Ssyrinx	return (NULL);
658216294Ssyrinx}
659216294Ssyrinx
660216294Ssyrinxstatic struct vacm_user *
661216294Ssyrinxvacm_get_next_user(const struct asn_oid *oid, uint sub)
662216294Ssyrinx{
663216294Ssyrinx	int32_t smodel;
664216294Ssyrinx	char uname[SNMP_ADM_STR32_SIZ];
665216294Ssyrinx	struct vacm_user *user;
666216294Ssyrinx
667216294Ssyrinx	if (oid->len - sub == 0)
668216294Ssyrinx		return (vacm_first_user());
669216294Ssyrinx
670216294Ssyrinx	if (vacm_user_index_decode(oid, sub, &smodel, uname) < 0)
671216294Ssyrinx		return (NULL);
672216294Ssyrinx
673216294Ssyrinx	for (user = vacm_first_user(); user != NULL; user = vacm_next_user(user))
674216294Ssyrinx		if (strcmp(uname, user->secname) == 0 &&
675216294Ssyrinx		    user->sec_model == smodel)
676216294Ssyrinx			return (vacm_next_user(user));
677216294Ssyrinx
678216294Ssyrinx	return (NULL);
679216294Ssyrinx}
680216294Ssyrinx
681216294Ssyrinxstatic void
682216294Ssyrinxvacm_append_access_rule_index(struct asn_oid *oid, uint sub,
683216294Ssyrinx    const struct vacm_access *acl)
684216294Ssyrinx{
685216294Ssyrinx	uint32_t i;
686216294Ssyrinx
687216294Ssyrinx	oid->len = sub + strlen(acl->group->groupname) +
688216294Ssyrinx	    strlen(acl->ctx_prefix) + 4;
689216294Ssyrinx
690216294Ssyrinx	oid->subs[sub] = strlen(acl->group->groupname);
691216294Ssyrinx	for (i = 1; i <= strlen(acl->group->groupname); i++)
692216294Ssyrinx		oid->subs[sub + i] = acl->group->groupname[i - 1];
693216294Ssyrinx	sub += strlen(acl->group->groupname) + 1;
694216294Ssyrinx
695216294Ssyrinx	oid->subs[sub] = strlen(acl->ctx_prefix);
696216294Ssyrinx	for (i = 1; i <= strlen(acl->ctx_prefix); i++)
697216294Ssyrinx		oid->subs[sub + i] = acl->ctx_prefix[i - 1];
698216294Ssyrinx	sub += strlen(acl->ctx_prefix) + 1;
699216294Ssyrinx	oid->subs[sub++] = acl->sec_model;
700216294Ssyrinx	oid->subs[sub] = acl->sec_level;
701216294Ssyrinx}
702216294Ssyrinx
703216294Ssyrinxstatic int
704216294Ssyrinxvacm_access_rule_index_decode(const struct asn_oid *oid, uint sub, char *gname,
705216294Ssyrinx    char *cprefix, int32_t *smodel, int32_t *slevel)
706216294Ssyrinx{
707216294Ssyrinx	uint32_t i;
708216294Ssyrinx
709216294Ssyrinx	if (oid->subs[sub] >= SNMP_ADM_STR32_SIZ)
710216294Ssyrinx		return (-1);
711216294Ssyrinx
712216294Ssyrinx	for (i = 0; i < oid->subs[sub]; i++)
713216294Ssyrinx		gname[i] = oid->subs[sub + i + 1];
714216294Ssyrinx	gname[i] = '\0';
715216294Ssyrinx	sub += strlen(gname) + 1;
716216294Ssyrinx
717216294Ssyrinx	if (oid->subs[sub] >= SNMP_ADM_STR32_SIZ)
718216294Ssyrinx		return (-1);
719216294Ssyrinx
720216294Ssyrinx	for (i = 0; i < oid->subs[sub]; i++)
721216294Ssyrinx		cprefix[i] = oid->subs[sub + i + 1];
722216294Ssyrinx	cprefix[i] = '\0';
723216294Ssyrinx	sub += strlen(cprefix) + 1;
724216294Ssyrinx
725216294Ssyrinx	*smodel = oid->subs[sub++];
726216294Ssyrinx	*slevel = oid->subs[sub];
727216294Ssyrinx
728216294Ssyrinx	return (0);
729216294Ssyrinx}
730216294Ssyrinx
731216294Ssyrinxstruct vacm_access *
732216294Ssyrinxvacm_get_access_rule(const struct asn_oid *oid, uint sub)
733216294Ssyrinx{
734216294Ssyrinx	int32_t smodel, slevel;
735216294Ssyrinx	char gname[SNMP_ADM_STR32_SIZ], prefix[SNMP_ADM_STR32_SIZ];
736216294Ssyrinx	struct vacm_access *acl;
737216294Ssyrinx
738216294Ssyrinx	if (vacm_access_rule_index_decode(oid, sub, gname, prefix, &smodel,
739216294Ssyrinx	    &slevel) < 0)
740216294Ssyrinx		return (NULL);
741216294Ssyrinx
742216294Ssyrinx	for (acl = vacm_first_access_rule(); acl != NULL;
743216294Ssyrinx	    acl = vacm_next_access_rule(acl))
744216294Ssyrinx		if (strcmp(gname, acl->group->groupname) == 0 &&
745216294Ssyrinx		    strcmp(prefix, acl->ctx_prefix) == 0 &&
746216294Ssyrinx		    smodel == acl->sec_model && slevel == acl->sec_level)
747216294Ssyrinx			return (acl);
748216294Ssyrinx
749216294Ssyrinx	return (NULL);
750216294Ssyrinx}
751216294Ssyrinx
752216294Ssyrinxstruct vacm_access *
753216294Ssyrinxvacm_get_next_access_rule(const struct asn_oid *oid __unused, uint sub __unused)
754216294Ssyrinx{
755216294Ssyrinx	int32_t smodel, slevel;
756216294Ssyrinx	char gname[SNMP_ADM_STR32_SIZ], prefix[SNMP_ADM_STR32_SIZ];
757216294Ssyrinx	struct vacm_access *acl;
758216294Ssyrinx
759216294Ssyrinx	if (oid->len - sub == 0)
760216294Ssyrinx		return (vacm_first_access_rule());
761216294Ssyrinx
762216294Ssyrinx	if (vacm_access_rule_index_decode(oid, sub, gname, prefix, &smodel,
763216294Ssyrinx	    &slevel) < 0)
764216294Ssyrinx		return (NULL);
765216294Ssyrinx
766216294Ssyrinx	for (acl = vacm_first_access_rule(); acl != NULL;
767216294Ssyrinx	    acl = vacm_next_access_rule(acl))
768216294Ssyrinx		if (strcmp(gname, acl->group->groupname) == 0 &&
769216294Ssyrinx		    strcmp(prefix, acl->ctx_prefix) == 0 &&
770216294Ssyrinx		    smodel == acl->sec_model && slevel == acl->sec_model)
771216294Ssyrinx			return (vacm_next_access_rule(acl));
772216294Ssyrinx
773216294Ssyrinx	return (NULL);
774216294Ssyrinx}
775216294Ssyrinx
776216294Ssyrinxstatic int
777216294Ssyrinxvacm_view_index_decode(const struct asn_oid *oid, uint sub, char *vname,
778216294Ssyrinx   struct asn_oid *view_oid)
779216294Ssyrinx{
780216294Ssyrinx	uint32_t i;
781216294Ssyrinx	int viod_off;
782216294Ssyrinx
783216294Ssyrinx	if (oid->subs[sub] >= SNMP_ADM_STR32_SIZ)
784216294Ssyrinx		return (-1);
785216294Ssyrinx
786216294Ssyrinx	for (i = 0; i < oid->subs[sub]; i++)
787216294Ssyrinx		vname[i] = oid->subs[sub + i + 1];
788216294Ssyrinx	vname[i] = '\0';
789216294Ssyrinx
790216294Ssyrinx	viod_off = sub + oid->subs[sub] + 1;
791216294Ssyrinx	if ((view_oid->len = oid->subs[viod_off]) > ASN_MAXOIDLEN)
792216294Ssyrinx		return (-1);
793216294Ssyrinx
794216294Ssyrinx	memcpy(&view_oid->subs[0], &oid->subs[viod_off + 1],
795216294Ssyrinx	    view_oid->len * sizeof(view_oid->subs[0]));
796216294Ssyrinx
797216294Ssyrinx	return (0);
798216294Ssyrinx}
799216294Ssyrinx
800216294Ssyrinxstatic void
801216294Ssyrinxvacm_append_viewindex(struct asn_oid *oid, uint sub, const struct vacm_view *view)
802216294Ssyrinx{
803216294Ssyrinx	uint32_t i;
804216294Ssyrinx
805216294Ssyrinx	oid->len = sub + strlen(view->viewname) + 1;
806216294Ssyrinx	oid->subs[sub] = strlen(view->viewname);
807216294Ssyrinx	for (i = 1; i <= strlen(view->viewname); i++)
808216294Ssyrinx		oid->subs[sub + i] = view->viewname[i - 1];
809216294Ssyrinx
810216294Ssyrinx	sub += strlen(view->viewname) + 1;
811216294Ssyrinx	oid->subs[sub] = view->subtree.len;
812216294Ssyrinx	oid->len++;
813216294Ssyrinx	asn_append_oid(oid, &view->subtree);
814216294Ssyrinx}
815216294Ssyrinx
816216294Ssyrinxstruct vacm_view *
817216294Ssyrinxvacm_get_view(const struct asn_oid *oid, uint sub)
818216294Ssyrinx{
819216294Ssyrinx	char vname[SNMP_ADM_STR32_SIZ];
820216294Ssyrinx	struct asn_oid subtree;
821216294Ssyrinx	struct vacm_view *view;
822216294Ssyrinx
823216294Ssyrinx	if (vacm_view_index_decode(oid, sub, vname, &subtree) < 0)
824216294Ssyrinx		return (NULL);
825216294Ssyrinx
826216294Ssyrinx	for (view = vacm_first_view(); view != NULL; view = vacm_next_view(view))
827216294Ssyrinx		if (strcmp(vname, view->viewname) == 0 &&
828216294Ssyrinx		    asn_compare_oid(&subtree, &view->subtree)== 0)
829216294Ssyrinx			return (view);
830216294Ssyrinx
831216294Ssyrinx	return (NULL);
832216294Ssyrinx}
833216294Ssyrinx
834216294Ssyrinxstruct vacm_view *
835216294Ssyrinxvacm_get_next_view(const struct asn_oid *oid, uint sub)
836216294Ssyrinx{
837216294Ssyrinx	char vname[SNMP_ADM_STR32_SIZ];
838216294Ssyrinx	struct asn_oid subtree;
839216294Ssyrinx	struct vacm_view *view;
840216294Ssyrinx
841216294Ssyrinx	if (oid->len - sub == 0)
842216294Ssyrinx		return (vacm_first_view());
843216294Ssyrinx
844216294Ssyrinx	if (vacm_view_index_decode(oid, sub, vname, &subtree) < 0)
845216294Ssyrinx		return (NULL);
846216294Ssyrinx
847216294Ssyrinx	for (view = vacm_first_view(); view != NULL; view = vacm_next_view(view))
848216294Ssyrinx		if (strcmp(vname, view->viewname) == 0 &&
849216294Ssyrinx		    asn_compare_oid(&subtree, &view->subtree)== 0)
850216294Ssyrinx			return (vacm_next_view(view));
851216294Ssyrinx
852216294Ssyrinx	return (NULL);
853216294Ssyrinx}
854216294Ssyrinx
855216294Ssyrinxstatic struct vacm_view *
856216294Ssyrinxvacm_get_view_by_name(u_char *octets, u_int len)
857216294Ssyrinx{
858216294Ssyrinx	struct vacm_view *view;
859216294Ssyrinx
860216294Ssyrinx	for (view = vacm_first_view(); view != NULL; view = vacm_next_view(view))
861216294Ssyrinx		if (strlen(view->viewname) == len &&
862216294Ssyrinx		    memcmp(octets, view->viewname, len) == 0)
863216294Ssyrinx			return (view);
864216294Ssyrinx
865216294Ssyrinx	return (NULL);
866216294Ssyrinx}
867216294Ssyrinx
868216294Ssyrinxstatic struct vacm_context *
869216294Ssyrinxvacm_get_context(const struct asn_oid *oid, uint sub)
870216294Ssyrinx{
871216294Ssyrinx	char cname[SNMP_ADM_STR32_SIZ];
872216294Ssyrinx	size_t cnamelen;
873216294Ssyrinx	u_int index_count;
874216294Ssyrinx	struct vacm_context *vacm_ctx;
875216294Ssyrinx
876216294Ssyrinx	if (oid->subs[sub] >= SNMP_ADM_STR32_SIZ)
877216294Ssyrinx		return (NULL);
878216294Ssyrinx
879216294Ssyrinx	index_count = 0;
880216294Ssyrinx	index_count = SNMP_INDEX(index_count, 1);
881216294Ssyrinx	if (index_decode(oid, sub, index_count, &cname, &cnamelen))
882216294Ssyrinx		return (NULL);
883216294Ssyrinx
884216294Ssyrinx	for (vacm_ctx = vacm_first_context(); vacm_ctx != NULL;
885216294Ssyrinx	    vacm_ctx = vacm_next_context(vacm_ctx))
886216294Ssyrinx		if (strcmp(cname, vacm_ctx->ctxname) == 0)
887216294Ssyrinx			return (vacm_ctx);
888216294Ssyrinx
889216294Ssyrinx	return (NULL);
890216294Ssyrinx}
891216294Ssyrinx
892216294Ssyrinxstatic struct vacm_context *
893216294Ssyrinxvacm_get_next_context(const struct asn_oid *oid, uint sub)
894216294Ssyrinx{
895216294Ssyrinx	char cname[SNMP_ADM_STR32_SIZ];
896216294Ssyrinx	size_t cnamelen;
897216294Ssyrinx	u_int index_count;
898216294Ssyrinx	struct vacm_context *vacm_ctx;
899216294Ssyrinx
900216294Ssyrinx	if (oid->len - sub == 0)
901216294Ssyrinx		return (vacm_first_context());
902216294Ssyrinx
903216294Ssyrinx	if (oid->subs[sub] >= SNMP_ADM_STR32_SIZ)
904216294Ssyrinx		return (NULL);
905216294Ssyrinx
906216294Ssyrinx	index_count = 0;
907216294Ssyrinx	index_count = SNMP_INDEX(index_count, 1);
908216294Ssyrinx	if (index_decode(oid, sub, index_count, &cname, &cnamelen))
909216294Ssyrinx		return (NULL);
910216294Ssyrinx
911216294Ssyrinx	for (vacm_ctx = vacm_first_context(); vacm_ctx != NULL;
912216294Ssyrinx	    vacm_ctx = vacm_next_context(vacm_ctx))
913216294Ssyrinx		if (strcmp(cname, vacm_ctx->ctxname) == 0)
914216294Ssyrinx			return (vacm_next_context(vacm_ctx));
915216294Ssyrinx
916216294Ssyrinx	return (NULL);
917216294Ssyrinx}
918216294Ssyrinx
919216294Ssyrinxstatic void
920216294Ssyrinxvacm_append_ctxindex(struct asn_oid *oid, uint sub,
921216294Ssyrinx    const struct vacm_context *ctx)
922216294Ssyrinx{
923216294Ssyrinx	uint32_t i;
924216294Ssyrinx
925216294Ssyrinx	oid->len = sub + strlen(ctx->ctxname) + 1;
926216294Ssyrinx	oid->subs[sub] = strlen(ctx->ctxname);
927216294Ssyrinx	for (i = 1; i <= strlen(ctx->ctxname); i++)
928216294Ssyrinx		oid->subs[sub + i] = ctx->ctxname[i - 1];
929216294Ssyrinx}
930216294Ssyrinx
931216294Ssyrinx/*
932216294Ssyrinx * VACM snmp module initialization hook.
933216294Ssyrinx * Returns 0 on success, < 0 on error.
934216294Ssyrinx */
935216294Ssyrinxstatic int
936216294Ssyrinxvacm_init(struct lmodule *mod, int argc __unused, char *argv[] __unused)
937216294Ssyrinx{
938216294Ssyrinx	vacm_module = mod;
939216294Ssyrinx	vacm_lock = random();
940216294Ssyrinx	vacm_groups_init();
941216294Ssyrinx
942216294Ssyrinx	/* XXX: TODO - initialize structures */
943216294Ssyrinx	return (0);
944216294Ssyrinx}
945216294Ssyrinx
946216294Ssyrinx/*
947216294Ssyrinx * VACM snmp module finalization hook.
948216294Ssyrinx */
949216294Ssyrinxstatic int
950216294Ssyrinxvacm_fini(void)
951216294Ssyrinx{
952216294Ssyrinx	/* XXX: TODO - cleanup */
953216294Ssyrinx	vacm_flush_contexts(reg_vacm);
954216294Ssyrinx	or_unregister(reg_vacm);
955216294Ssyrinx
956216294Ssyrinx	return (0);
957216294Ssyrinx}
958216294Ssyrinx
959216294Ssyrinx/*
960216294Ssyrinx * VACM snmp module start operation.
961216294Ssyrinx */
962216294Ssyrinxstatic void
963216294Ssyrinxvacm_start(void)
964216294Ssyrinx{
965216294Ssyrinx	static char dflt_ctx[] = "";
966216294Ssyrinx
967216294Ssyrinx	reg_vacm = or_register(&oid_vacm,
968216294Ssyrinx	    "The MIB module for managing SNMP View-based Access Control Model.",
969216294Ssyrinx	    vacm_module);
970216294Ssyrinx
971216294Ssyrinx	(void)vacm_add_context(dflt_ctx, reg_vacm);
972216294Ssyrinx}
973216294Ssyrinx
974216294Ssyrinxstatic void
975216294Ssyrinxvacm_dump(void)
976216294Ssyrinx{
977216294Ssyrinx	struct vacm_context *vacmctx;
978216294Ssyrinx	struct vacm_user *vuser;
979216294Ssyrinx	struct vacm_access *vacl;
980216294Ssyrinx	struct vacm_view *view;
981216294Ssyrinx	static char oidbuf[ASN_OIDSTRLEN];
982216294Ssyrinx
983216294Ssyrinx	syslog(LOG_ERR, "\n");
984216294Ssyrinx	syslog(LOG_ERR, "Context list:");
985216294Ssyrinx	for (vacmctx = vacm_first_context(); vacmctx != NULL;
986216294Ssyrinx	    vacmctx = vacm_next_context(vacmctx))
987216294Ssyrinx		syslog(LOG_ERR, "Context \"%s\", module id %d",
988216294Ssyrinx		    vacmctx->ctxname, vacmctx->regid);
989216294Ssyrinx
990216294Ssyrinx	syslog(LOG_ERR, "VACM users:");
991216294Ssyrinx	for (vuser = vacm_first_user(); vuser != NULL;
992216294Ssyrinx	    vuser = vacm_next_user(vuser))
993216294Ssyrinx		syslog(LOG_ERR, "Uname %s, Group %s, model %d", vuser->secname,
994216294Ssyrinx		    vuser->group!= NULL?vuser->group->groupname:"Unknown",
995216294Ssyrinx		    vuser->sec_model);
996216294Ssyrinx
997216294Ssyrinx	syslog(LOG_ERR, "VACM Access rules:");
998216294Ssyrinx	for (vacl = vacm_first_access_rule(); vacl != NULL;
999216294Ssyrinx	    vacl = vacm_next_access_rule(vacl))
1000216294Ssyrinx		syslog(LOG_ERR, "Group %s, CtxPrefix %s, Model %d, Level %d, "
1001216294Ssyrinx		    "RV %s, WR %s, NV %s", vacl->group!=NULL?
1002216294Ssyrinx		    vacl->group->groupname:"Unknown", vacl->ctx_prefix,
1003216294Ssyrinx		    vacl->sec_model, vacl->sec_level, vacl->read_view!=NULL?
1004216294Ssyrinx		    vacl->read_view->viewname:"None", vacl->write_view!=NULL?
1005216294Ssyrinx		    vacl->write_view->viewname:"None", vacl->notify_view!=NULL?
1006216294Ssyrinx		    vacl->notify_view->viewname:"None");
1007216294Ssyrinx
1008216294Ssyrinx	syslog(LOG_ERR, "VACM Views:");
1009216294Ssyrinx	for (view = vacm_first_view(); view != NULL; view = vacm_next_view(view))
1010216294Ssyrinx		syslog(LOG_ERR, "View %s, Tree %s - %s", view->viewname,
1011216294Ssyrinx		    asn_oid2str_r(&view->subtree, oidbuf), view->exclude?
1012216294Ssyrinx		    "excluded":"included");
1013216294Ssyrinx}
1014216294Ssyrinx
1015216294Ssyrinxconst char vacm_comment[] = \
1016216294Ssyrinx"This module implements SNMP View-based Access Control Model defined in RFC 3415.";
1017216294Ssyrinx
1018216294Ssyrinxconst struct snmp_module config = {
1019216294Ssyrinx	.comment =	vacm_comment,
1020216294Ssyrinx	.init =		vacm_init,
1021216294Ssyrinx	.fini =		vacm_fini,
1022216294Ssyrinx	.start =	vacm_start,
1023216294Ssyrinx	.tree =		vacm_ctree,
1024216294Ssyrinx	.dump =		vacm_dump,
1025216294Ssyrinx	.tree_size =	vacm_CTREE_SIZE,
1026216294Ssyrinx};
1027