Merge commit 'b4bf0cf0458759c67920a031021a9d96cd683cfe'
[unleashed.git] / kernel / syscall / auditsys.c
blob7dfe70824cf4759c5cbd76cec4295ea45f7bf4f9
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
25 #include <sys/systm.h>
26 #include <sys/errno.h>
27 #include <sys/policy.h>
29 #include <c2/audit.h>
30 #include <c2/audit_kernel.h>
31 #include <c2/audit_record.h>
33 #define CLEAR_VAL -1
35 extern kmutex_t pidlock;
37 uint32_t audit_policy; /* global audit policies in force */
40 /*ARGSUSED1*/
41 int
42 auditsys(struct auditcalls *uap, rval_t *rvp)
44 int err;
45 int result = 0;
47 if (audit_active == C2AUDIT_DISABLED)
48 return (ENOTSUP);
50 switch (uap->code) {
51 case BSM_GETAUID:
52 result = getauid((caddr_t)uap->a1);
53 break;
54 case BSM_SETAUID:
55 result = setauid((caddr_t)uap->a1);
56 break;
57 case BSM_GETAUDIT:
58 result = getaudit((caddr_t)uap->a1);
59 break;
60 case BSM_GETAUDIT_ADDR:
61 result = getaudit_addr((caddr_t)uap->a1, (int)uap->a2);
62 break;
63 case BSM_SETAUDIT:
64 result = setaudit((caddr_t)uap->a1);
65 break;
66 case BSM_SETAUDIT_ADDR:
67 result = setaudit_addr((caddr_t)uap->a1, (int)uap->a2);
68 break;
69 case BSM_AUDITCTL:
70 result = auditctl((int)uap->a1, (caddr_t)uap->a2, (int)uap->a3);
71 break;
72 case BSM_AUDIT:
73 if (audit_active == C2AUDIT_UNLOADED)
74 return (0);
75 result = audit((caddr_t)uap->a1, (int)uap->a2);
76 break;
77 case BSM_AUDITDOOR:
78 if (audit_active == C2AUDIT_LOADED) {
79 result = auditdoor((int)uap->a1);
80 break;
82 /* FALLTHROUGH */
83 default:
84 if (audit_active == C2AUDIT_LOADED) {
85 result = EINVAL;
86 break;
88 /* Return a different error when not privileged */
89 err = secpolicy_audit_config(CRED());
90 if (err == 0)
91 return (EINVAL);
92 else
93 return (err);
95 rvp->r_vals = result;
96 return (result);
100 * Return the audit user ID for the current process. Currently only
101 * the privileged processes may see the audit id. That may change.
102 * If copyout is unsucessful return EFAULT.
105 getauid(caddr_t auid_p)
107 const auditinfo_addr_t *ainfo;
109 if (secpolicy_audit_getattr(CRED(), B_FALSE) != 0)
110 return (EPERM);
112 ainfo = crgetauinfo(CRED());
113 if (ainfo == NULL)
114 return (EINVAL);
116 if (copyout(&ainfo->ai_auid, auid_p, sizeof (au_id_t)))
117 return (EFAULT);
119 return (0);
123 * Set the audit userid, for a process. This can only be changed by
124 * privileged processes. The audit userid is inherited across forks & execs.
125 * Passed in is a pointer to the au_id_t; if copyin unsuccessful return EFAULT.
128 setauid(caddr_t auid_p)
130 proc_t *p;
131 au_id_t auid;
132 cred_t *newcred;
133 auditinfo_addr_t *auinfo;
135 if (secpolicy_audit_config(CRED()) != 0)
136 return (EPERM);
138 if (copyin(auid_p, &auid, sizeof (au_id_t))) {
139 return (EFAULT);
142 newcred = cralloc();
143 if ((auinfo = crgetauinfo_modifiable(newcred)) == NULL) {
144 crfree(newcred);
145 return (EINVAL);
148 /* grab p_crlock and switch to new cred */
149 p = curproc;
150 mutex_enter(&p->p_crlock);
151 crcopy_to(p->p_cred, newcred);
152 p->p_cred = newcred;
154 auinfo->ai_auid = auid; /* update the auid */
156 /* unlock and broadcast the cred changes */
157 mutex_exit(&p->p_crlock);
158 crset(p, newcred);
160 return (0);
164 * Get the audit state information from the current process.
165 * Return EFAULT if copyout fails.
168 getaudit(caddr_t info_p)
170 STRUCT_DECL(auditinfo, info);
171 const auditinfo_addr_t *ainfo;
172 model_t model;
174 if (secpolicy_audit_getattr(CRED(), B_FALSE) != 0)
175 return (EPERM);
177 model = get_udatamodel();
178 STRUCT_INIT(info, model);
180 ainfo = crgetauinfo(CRED());
181 if (ainfo == NULL)
182 return (EINVAL);
184 /* trying to read a process with an IPv6 address? */
185 if (ainfo->ai_termid.at_type == AU_IPv6)
186 return (EOVERFLOW);
188 STRUCT_FSET(info, ai_auid, ainfo->ai_auid);
189 STRUCT_FSET(info, ai_mask, ainfo->ai_mask);
190 #ifdef _LP64
191 if (model == DATAMODEL_ILP32) {
192 dev32_t dev;
193 /* convert internal 64 bit form to 32 bit version */
194 if (cmpldev(&dev, ainfo->ai_termid.at_port) == 0) {
195 return (EOVERFLOW);
197 STRUCT_FSET(info, ai_termid.port, dev);
198 } else
199 STRUCT_FSET(info, ai_termid.port, ainfo->ai_termid.at_port);
200 #else
201 STRUCT_FSET(info, ai_termid.port, ainfo->ai_termid.at_port);
202 #endif
203 STRUCT_FSET(info, ai_termid.machine, ainfo->ai_termid.at_addr[0]);
204 STRUCT_FSET(info, ai_asid, ainfo->ai_asid);
206 if (copyout(STRUCT_BUF(info), info_p, STRUCT_SIZE(info)))
207 return (EFAULT);
209 return (0);
213 * Get the audit state information from the current process.
214 * Return EFAULT if copyout fails.
217 getaudit_addr(caddr_t info_p, int len)
219 STRUCT_DECL(auditinfo_addr, info);
220 const auditinfo_addr_t *ainfo;
221 model_t model;
223 if (secpolicy_audit_getattr(CRED(), B_FALSE) != 0)
224 return (EPERM);
226 model = get_udatamodel();
227 STRUCT_INIT(info, model);
229 if (len < STRUCT_SIZE(info))
230 return (EOVERFLOW);
232 ainfo = crgetauinfo(CRED());
234 if (ainfo == NULL)
235 return (EINVAL);
237 STRUCT_FSET(info, ai_auid, ainfo->ai_auid);
238 STRUCT_FSET(info, ai_mask, ainfo->ai_mask);
239 #ifdef _LP64
240 if (model == DATAMODEL_ILP32) {
241 dev32_t dev;
242 /* convert internal 64 bit form to 32 bit version */
243 if (cmpldev(&dev, ainfo->ai_termid.at_port) == 0) {
244 return (EOVERFLOW);
246 STRUCT_FSET(info, ai_termid.at_port, dev);
247 } else
248 STRUCT_FSET(info, ai_termid.at_port, ainfo->ai_termid.at_port);
249 #else
250 STRUCT_FSET(info, ai_termid.at_port, ainfo->ai_termid.at_port);
251 #endif
252 STRUCT_FSET(info, ai_termid.at_type, ainfo->ai_termid.at_type);
253 STRUCT_FSET(info, ai_termid.at_addr[0], ainfo->ai_termid.at_addr[0]);
254 STRUCT_FSET(info, ai_termid.at_addr[1], ainfo->ai_termid.at_addr[1]);
255 STRUCT_FSET(info, ai_termid.at_addr[2], ainfo->ai_termid.at_addr[2]);
256 STRUCT_FSET(info, ai_termid.at_addr[3], ainfo->ai_termid.at_addr[3]);
257 STRUCT_FSET(info, ai_asid, ainfo->ai_asid);
259 if (copyout(STRUCT_BUF(info), info_p, STRUCT_SIZE(info)))
260 return (EFAULT);
262 return (0);
266 * Set the audit state information for the current process.
267 * Return EFAULT if copyout fails.
270 setaudit(caddr_t info_p)
272 STRUCT_DECL(auditinfo, info);
273 proc_t *p;
274 cred_t *newcred;
275 model_t model;
276 auditinfo_addr_t *ainfo;
278 if (secpolicy_audit_config(CRED()) != 0)
279 return (EPERM);
281 model = get_udatamodel();
282 STRUCT_INIT(info, model);
284 if (copyin(info_p, STRUCT_BUF(info), STRUCT_SIZE(info)))
285 return (EFAULT);
287 newcred = cralloc();
288 if ((ainfo = crgetauinfo_modifiable(newcred)) == NULL) {
289 crfree(newcred);
290 return (EINVAL);
293 /* grab p_crlock and switch to new cred */
294 p = curproc;
295 mutex_enter(&p->p_crlock);
296 crcopy_to(p->p_cred, newcred);
297 p->p_cred = newcred;
299 /* Set audit mask, id, termid and session id as specified */
300 ainfo->ai_auid = STRUCT_FGET(info, ai_auid);
301 #ifdef _LP64
302 /* only convert to 64 bit if coming from a 32 bit binary */
303 if (model == DATAMODEL_ILP32)
304 ainfo->ai_termid.at_port =
305 DEVEXPL(STRUCT_FGET(info, ai_termid.port));
306 else
307 ainfo->ai_termid.at_port = STRUCT_FGET(info, ai_termid.port);
308 #else
309 ainfo->ai_termid.at_port = STRUCT_FGET(info, ai_termid.port);
310 #endif
311 ainfo->ai_termid.at_type = AU_IPv4;
312 ainfo->ai_termid.at_addr[0] = STRUCT_FGET(info, ai_termid.machine);
313 ainfo->ai_asid = STRUCT_FGET(info, ai_asid);
314 ainfo->ai_mask = STRUCT_FGET(info, ai_mask);
316 /* unlock and broadcast the cred changes */
317 mutex_exit(&p->p_crlock);
318 crset(p, newcred);
320 return (0);
324 * Set the audit state information for the current process.
325 * Return EFAULT if copyin fails.
328 setaudit_addr(caddr_t info_p, int len)
330 STRUCT_DECL(auditinfo_addr, info);
331 proc_t *p;
332 cred_t *newcred;
333 model_t model;
334 int i;
335 int type;
336 auditinfo_addr_t *ainfo;
338 if (secpolicy_audit_config(CRED()) != 0)
339 return (EPERM);
341 model = get_udatamodel();
342 STRUCT_INIT(info, model);
344 if (len < STRUCT_SIZE(info))
345 return (EOVERFLOW);
347 if (copyin(info_p, STRUCT_BUF(info), STRUCT_SIZE(info)))
348 return (EFAULT);
350 type = STRUCT_FGET(info, ai_termid.at_type);
351 if ((type != AU_IPv4) && (type != AU_IPv6))
352 return (EINVAL);
354 newcred = cralloc();
355 if ((ainfo = crgetauinfo_modifiable(newcred)) == NULL) {
356 crfree(newcred);
357 return (EINVAL);
360 /* grab p_crlock and switch to new cred */
361 p = curproc;
362 mutex_enter(&p->p_crlock);
363 crcopy_to(p->p_cred, newcred);
364 p->p_cred = newcred;
366 /* Set audit mask, id, termid and session id as specified */
367 ainfo->ai_auid = STRUCT_FGET(info, ai_auid);
368 ainfo->ai_mask = STRUCT_FGET(info, ai_mask);
369 #ifdef _LP64
370 /* only convert to 64 bit if coming from a 32 bit binary */
371 if (model == DATAMODEL_ILP32)
372 ainfo->ai_termid.at_port =
373 DEVEXPL(STRUCT_FGET(info, ai_termid.at_port));
374 else
375 ainfo->ai_termid.at_port = STRUCT_FGET(info, ai_termid.at_port);
376 #else
377 ainfo->ai_termid.at_port = STRUCT_FGET(info, ai_termid.at_port);
378 #endif
379 ainfo->ai_termid.at_type = type;
380 bzero(&ainfo->ai_termid.at_addr[0], sizeof (ainfo->ai_termid.at_addr));
381 for (i = 0; i < (type/sizeof (int)); i++)
382 ainfo->ai_termid.at_addr[i] =
383 STRUCT_FGET(info, ai_termid.at_addr[i]);
385 if (ainfo->ai_termid.at_type == AU_IPv6 &&
386 IN6_IS_ADDR_V4MAPPED(((in6_addr_t *)ainfo->ai_termid.at_addr))) {
387 ainfo->ai_termid.at_type = AU_IPv4;
388 ainfo->ai_termid.at_addr[0] = ainfo->ai_termid.at_addr[3];
389 ainfo->ai_termid.at_addr[1] = 0;
390 ainfo->ai_termid.at_addr[2] = 0;
391 ainfo->ai_termid.at_addr[3] = 0;
394 ainfo->ai_asid = STRUCT_FGET(info, ai_asid);
396 /* unlock and broadcast the cred changes */
397 mutex_exit(&p->p_crlock);
398 crset(p, newcred);
400 return (0);
404 * Get the global policy flag
406 static int
407 getpolicy(caddr_t data)
409 uint32_t policy;
410 au_kcontext_t *kctx = GET_KCTX_PZ;
412 policy = audit_policy | kctx->auk_policy;
414 if (copyout(&policy, data, sizeof (policy)))
415 return (EFAULT);
416 return (0);
420 * Set the global and local policy flags
422 * The global flags only make sense from the global zone;
423 * the local flags depend on the AUDIT_PERZONE policy:
424 * if the perzone policy is set, then policy is set separately
425 * per zone, else held only in the global zone.
427 * The initial value of a local zone's policy flag is determined
428 * by the value of the global zone's flags at the time the
429 * local zone is created.
431 * While auditconfig(8) allows setting and unsetting policies one bit
432 * at a time, the mask passed in from auditconfig() is created by a
433 * syscall to getpolicy and then modified based on the auditconfig()
434 * cmd line, so the input policy value is used to replace the existing
435 * policy.
437 static int
438 setpolicy(caddr_t data)
440 uint32_t policy;
441 au_kcontext_t *kctx;
443 if (copyin(data, &policy, sizeof (policy)))
444 return (EFAULT);
446 kctx = GET_KCTX_NGZ;
448 if (INGLOBALZONE(curproc)) {
449 if (policy & ~(AUDIT_GLOBAL | AUDIT_LOCAL))
450 return (EINVAL);
452 audit_policy = policy & AUDIT_GLOBAL;
453 } else {
454 if (!(audit_policy & AUDIT_PERZONE))
455 return (EINVAL);
457 if (policy & ~AUDIT_LOCAL) /* global bits are a no-no */
458 return (EINVAL);
460 kctx->auk_policy = policy & AUDIT_LOCAL;
463 * auk_current_vp is NULL before auditd starts (or during early
464 * auditd starup) or if auditd is halted; in either case,
465 * notification of a policy change is not needed, since auditd
466 * reads policy as it comes up. The error return from au_doormsg()
467 * is ignored to avoid a race condition -- for example if auditd
468 * segv's, the audit state may be "auditing" but the door may
469 * be closed. Returning an error if the door is open makes it
470 * impossible for Greenline to restart auditd.
472 if (kctx->auk_current_vp != NULL)
473 (void) au_doormsg(kctx, AU_DBUF_POLICY, &policy);
476 * Wake up anyone who might have blocked on full audit
477 * partitions. audit daemons need to set AUDIT_FULL when no
478 * space so we can tell if we should start dropping records.
480 mutex_enter(&(kctx->auk_queue.lock));
482 if ((policy & (AUDIT_CNT | AUDIT_SCNT) &&
483 (kctx->auk_queue.cnt >= kctx->auk_queue.hiwater)))
484 cv_broadcast(&(kctx->auk_queue.write_cv));
486 mutex_exit(&(kctx->auk_queue.lock));
488 return (0);
491 static int
492 getamask(caddr_t data)
494 au_kcontext_t *kctx;
496 kctx = GET_KCTX_PZ;
498 if (copyout(&kctx->auk_info.ai_amask, data, sizeof (au_mask_t)))
499 return (EFAULT);
501 return (0);
504 static int
505 setamask(caddr_t data)
507 au_mask_t mask;
508 au_kcontext_t *kctx;
510 if (!(audit_policy & AUDIT_PERZONE) && !INGLOBALZONE(curproc))
511 return (EINVAL);
513 kctx = GET_KCTX_NGZ;
515 if (copyin(data, &mask, sizeof (au_mask_t)))
516 return (EFAULT);
518 kctx->auk_info.ai_amask = mask;
519 return (0);
522 static int
523 getkmask(caddr_t data)
525 au_kcontext_t *kctx;
527 kctx = GET_KCTX_PZ;
529 if (copyout(&kctx->auk_info.ai_namask, data, sizeof (au_mask_t)))
530 return (EFAULT);
531 return (0);
534 static int
535 setkmask(caddr_t data)
537 au_mask_t mask;
538 au_kcontext_t *kctx;
540 if (!(audit_policy & AUDIT_PERZONE) && !INGLOBALZONE(curproc))
541 return (EINVAL);
543 kctx = GET_KCTX_NGZ;
545 if (copyin(data, &mask, sizeof (au_mask_t)))
546 return (EFAULT);
548 kctx->auk_info.ai_namask = mask;
549 return (0);
552 static int
553 getkaudit(caddr_t info_p, int len)
555 STRUCT_DECL(auditinfo_addr, info);
556 model_t model;
557 au_kcontext_t *kctx = GET_KCTX_PZ;
559 model = get_udatamodel();
560 STRUCT_INIT(info, model);
562 if (len < STRUCT_SIZE(info))
563 return (EOVERFLOW);
565 STRUCT_FSET(info, ai_auid, kctx->auk_info.ai_auid);
566 STRUCT_FSET(info, ai_mask, kctx->auk_info.ai_namask);
567 #ifdef _LP64
568 if (model == DATAMODEL_ILP32) {
569 dev32_t dev;
570 /* convert internal 64 bit form to 32 bit version */
571 if (cmpldev(&dev, kctx->auk_info.ai_termid.at_port) == 0) {
572 return (EOVERFLOW);
574 STRUCT_FSET(info, ai_termid.at_port, dev);
575 } else {
576 STRUCT_FSET(info, ai_termid.at_port,
577 kctx->auk_info.ai_termid.at_port);
579 #else
580 STRUCT_FSET(info, ai_termid.at_port,
581 kctx->auk_info.ai_termid.at_port);
582 #endif
583 STRUCT_FSET(info, ai_termid.at_type,
584 kctx->auk_info.ai_termid.at_type);
585 STRUCT_FSET(info, ai_termid.at_addr[0],
586 kctx->auk_info.ai_termid.at_addr[0]);
587 STRUCT_FSET(info, ai_termid.at_addr[1],
588 kctx->auk_info.ai_termid.at_addr[1]);
589 STRUCT_FSET(info, ai_termid.at_addr[2],
590 kctx->auk_info.ai_termid.at_addr[2]);
591 STRUCT_FSET(info, ai_termid.at_addr[3],
592 kctx->auk_info.ai_termid.at_addr[3]);
593 STRUCT_FSET(info, ai_asid, kctx->auk_info.ai_asid);
595 if (copyout(STRUCT_BUF(info), info_p, STRUCT_SIZE(info)))
596 return (EFAULT);
598 return (0);
602 * the host address for AUDIT_PERZONE == 0 is that of the global
603 * zone and for local zones it is of the current zone.
605 static int
606 setkaudit(caddr_t info_p, int len)
608 STRUCT_DECL(auditinfo_addr, info);
609 model_t model;
610 au_kcontext_t *kctx;
612 if (!(audit_policy & AUDIT_PERZONE) && !INGLOBALZONE(curproc))
613 return (EINVAL);
615 kctx = GET_KCTX_NGZ;
617 model = get_udatamodel();
618 STRUCT_INIT(info, model);
620 if (len < STRUCT_SIZE(info))
621 return (EOVERFLOW);
623 if (copyin(info_p, STRUCT_BUF(info), STRUCT_SIZE(info)))
624 return (EFAULT);
626 if ((STRUCT_FGET(info, ai_termid.at_type) != AU_IPv4) &&
627 (STRUCT_FGET(info, ai_termid.at_type) != AU_IPv6))
628 return (EINVAL);
630 /* Set audit mask, termid and session id as specified */
631 kctx->auk_info.ai_auid = STRUCT_FGET(info, ai_auid);
632 kctx->auk_info.ai_namask = STRUCT_FGET(info, ai_mask);
633 #ifdef _LP64
634 /* only convert to 64 bit if coming from a 32 bit binary */
635 if (model == DATAMODEL_ILP32)
636 kctx->auk_info.ai_termid.at_port =
637 DEVEXPL(STRUCT_FGET(info, ai_termid.at_port));
638 else
639 kctx->auk_info.ai_termid.at_port =
640 STRUCT_FGET(info, ai_termid.at_port);
641 #else
642 kctx->auk_info.ai_termid.at_port = STRUCT_FGET(info, ai_termid.at_port);
643 #endif
644 kctx->auk_info.ai_termid.at_type = STRUCT_FGET(info, ai_termid.at_type);
645 bzero(&kctx->auk_info.ai_termid.at_addr[0],
646 sizeof (kctx->auk_info.ai_termid.at_addr));
647 kctx->auk_info.ai_termid.at_addr[0] =
648 STRUCT_FGET(info, ai_termid.at_addr[0]);
649 kctx->auk_info.ai_termid.at_addr[1] =
650 STRUCT_FGET(info, ai_termid.at_addr[1]);
651 kctx->auk_info.ai_termid.at_addr[2] =
652 STRUCT_FGET(info, ai_termid.at_addr[2]);
653 kctx->auk_info.ai_termid.at_addr[3] =
654 STRUCT_FGET(info, ai_termid.at_addr[3]);
655 kctx->auk_info.ai_asid = STRUCT_FGET(info, ai_asid);
657 if (kctx->auk_info.ai_termid.at_type == AU_IPv6 &&
658 IN6_IS_ADDR_V4MAPPED(
659 ((in6_addr_t *)kctx->auk_info.ai_termid.at_addr))) {
660 kctx->auk_info.ai_termid.at_type = AU_IPv4;
661 kctx->auk_info.ai_termid.at_addr[0] =
662 kctx->auk_info.ai_termid.at_addr[3];
663 kctx->auk_info.ai_termid.at_addr[1] = 0;
664 kctx->auk_info.ai_termid.at_addr[2] = 0;
665 kctx->auk_info.ai_termid.at_addr[3] = 0;
667 if (kctx->auk_info.ai_termid.at_type == AU_IPv6)
668 kctx->auk_hostaddr_valid = IN6_IS_ADDR_UNSPECIFIED(
669 (in6_addr_t *)kctx->auk_info.ai_termid.at_addr) ? 0 : 1;
670 else
671 kctx->auk_hostaddr_valid =
672 (kctx->auk_info.ai_termid.at_addr[0] ==
673 htonl(INADDR_ANY)) ? 0 : 1;
675 return (0);
678 static int
679 getqctrl(caddr_t data)
681 au_kcontext_t *kctx = GET_KCTX_PZ;
682 STRUCT_DECL(au_qctrl, qctrl);
683 STRUCT_INIT(qctrl, get_udatamodel());
685 mutex_enter(&(kctx->auk_queue.lock));
686 STRUCT_FSET(qctrl, aq_hiwater, kctx->auk_queue.hiwater);
687 STRUCT_FSET(qctrl, aq_lowater, kctx->auk_queue.lowater);
688 STRUCT_FSET(qctrl, aq_bufsz, kctx->auk_queue.bufsz);
689 STRUCT_FSET(qctrl, aq_delay, kctx->auk_queue.delay);
690 mutex_exit(&(kctx->auk_queue.lock));
692 if (copyout(STRUCT_BUF(qctrl), data, STRUCT_SIZE(qctrl)))
693 return (EFAULT);
695 return (0);
698 static int
699 setqctrl(caddr_t data)
701 au_kcontext_t *kctx;
702 struct au_qctrl qctrl_tmp;
703 STRUCT_DECL(au_qctrl, qctrl);
704 STRUCT_INIT(qctrl, get_udatamodel());
706 if (!(audit_policy & AUDIT_PERZONE) && !INGLOBALZONE(curproc))
707 return (EINVAL);
708 kctx = GET_KCTX_NGZ;
710 if (copyin(data, STRUCT_BUF(qctrl), STRUCT_SIZE(qctrl)))
711 return (EFAULT);
713 qctrl_tmp.aq_hiwater = (size_t)STRUCT_FGET(qctrl, aq_hiwater);
714 qctrl_tmp.aq_lowater = (size_t)STRUCT_FGET(qctrl, aq_lowater);
715 qctrl_tmp.aq_bufsz = (size_t)STRUCT_FGET(qctrl, aq_bufsz);
716 qctrl_tmp.aq_delay = (clock_t)STRUCT_FGET(qctrl, aq_delay);
718 /* enforce sane values */
720 if (qctrl_tmp.aq_hiwater <= qctrl_tmp.aq_lowater)
721 return (EINVAL);
723 if (qctrl_tmp.aq_hiwater < AQ_LOWATER)
724 return (EINVAL);
726 if (qctrl_tmp.aq_hiwater > AQ_MAXHIGH)
727 return (EINVAL);
729 if (qctrl_tmp.aq_bufsz < AQ_BUFSZ)
730 return (EINVAL);
732 if (qctrl_tmp.aq_bufsz > AQ_MAXBUFSZ)
733 return (EINVAL);
735 if (qctrl_tmp.aq_delay == 0)
736 return (EINVAL);
738 if (qctrl_tmp.aq_delay > AQ_MAXDELAY)
739 return (EINVAL);
741 /* update everything at once so things are consistant */
742 mutex_enter(&(kctx->auk_queue.lock));
743 kctx->auk_queue.hiwater = qctrl_tmp.aq_hiwater;
744 kctx->auk_queue.lowater = qctrl_tmp.aq_lowater;
745 kctx->auk_queue.bufsz = qctrl_tmp.aq_bufsz;
746 kctx->auk_queue.delay = qctrl_tmp.aq_delay;
748 if (kctx->auk_queue.rd_block &&
749 kctx->auk_queue.cnt > kctx->auk_queue.lowater)
750 cv_broadcast(&(kctx->auk_queue.read_cv));
752 if (kctx->auk_queue.wt_block &&
753 kctx->auk_queue.cnt < kctx->auk_queue.hiwater)
754 cv_broadcast(&(kctx->auk_queue.write_cv));
756 mutex_exit(&(kctx->auk_queue.lock));
758 return (0);
761 static int
762 getcwd(caddr_t data, int length)
764 struct p_audit_data *pad;
765 struct audit_path *app;
766 int pathlen;
768 pad = P2A(curproc);
769 ASSERT(pad != NULL);
771 mutex_enter(&(pad->pad_lock));
772 app = pad->pad_cwd;
773 au_pathhold(app);
774 mutex_exit(&(pad->pad_lock));
776 pathlen = app->audp_sect[1] - app->audp_sect[0];
777 if (pathlen > length) {
778 au_pathrele(app);
779 return (E2BIG);
782 if (copyout(app->audp_sect[0], data, pathlen)) {
783 au_pathrele(app);
784 return (EFAULT);
787 au_pathrele(app);
788 return (0);
791 static int
792 getcar(caddr_t data, int length)
794 struct p_audit_data *pad;
795 struct audit_path *app;
796 int pathlen;
798 pad = P2A(curproc);
799 ASSERT(pad != NULL);
801 mutex_enter(&(pad->pad_lock));
802 app = pad->pad_root;
803 au_pathhold(app);
804 mutex_exit(&(pad->pad_lock));
806 pathlen = app->audp_sect[1] - app->audp_sect[0];
807 if (pathlen > length) {
808 au_pathrele(app);
809 return (E2BIG);
812 if (copyout(app->audp_sect[0], data, pathlen)) {
813 au_pathrele(app);
814 return (EFAULT);
817 au_pathrele(app);
818 return (0);
821 static int
822 getstat(caddr_t data)
824 au_kcontext_t *kctx = GET_KCTX_PZ;
826 membar_consumer();
828 if (copyout((caddr_t)&(kctx->auk_statistics), data, sizeof (au_stat_t)))
829 return (EFAULT);
830 return (0);
833 static int
834 setstat(caddr_t data)
836 au_kcontext_t *kctx = GET_KCTX_PZ;
837 au_stat_t au_stat;
839 if (!(audit_policy & AUDIT_PERZONE) && !INGLOBALZONE(curproc))
840 return (EINVAL);
842 if (copyin(data, &au_stat, sizeof (au_stat_t)))
843 return (EFAULT);
845 if (au_stat.as_generated == CLEAR_VAL)
846 kctx->auk_statistics.as_generated = 0;
847 if (au_stat.as_nonattrib == CLEAR_VAL)
848 kctx->auk_statistics.as_nonattrib = 0;
849 if (au_stat.as_kernel == CLEAR_VAL)
850 kctx->auk_statistics.as_kernel = 0;
851 if (au_stat.as_audit == CLEAR_VAL)
852 kctx->auk_statistics.as_audit = 0;
853 if (au_stat.as_auditctl == CLEAR_VAL)
854 kctx->auk_statistics.as_auditctl = 0;
855 if (au_stat.as_enqueue == CLEAR_VAL)
856 kctx->auk_statistics.as_enqueue = 0;
857 if (au_stat.as_written == CLEAR_VAL)
858 kctx->auk_statistics.as_written = 0;
859 if (au_stat.as_wblocked == CLEAR_VAL)
860 kctx->auk_statistics.as_wblocked = 0;
861 if (au_stat.as_rblocked == CLEAR_VAL)
862 kctx->auk_statistics.as_rblocked = 0;
863 if (au_stat.as_dropped == CLEAR_VAL)
864 kctx->auk_statistics.as_dropped = 0;
865 if (au_stat.as_totalsize == CLEAR_VAL)
866 kctx->auk_statistics.as_totalsize = 0;
868 membar_producer();
870 return (0);
874 static int
875 setumask(caddr_t data)
877 STRUCT_DECL(auditinfo, user_info);
878 struct proc *p;
879 const auditinfo_addr_t *ainfo;
880 model_t model;
882 /* setumask not applicable in non-global zones without perzone policy */
883 if (!(audit_policy & AUDIT_PERZONE) && (!INGLOBALZONE(curproc)))
884 return (EINVAL);
886 model = get_udatamodel();
887 STRUCT_INIT(user_info, model);
889 if (copyin(data, STRUCT_BUF(user_info), STRUCT_SIZE(user_info)))
890 return (EFAULT);
892 mutex_enter(&pidlock); /* lock the process queue against updates */
893 for (p = practive; p != NULL; p = p->p_next) {
894 cred_t *cr;
896 /* if in non-global zone only modify processes in same zone */
897 if (!HASZONEACCESS(curproc, p->p_zone->zone_id))
898 continue;
900 mutex_enter(&p->p_lock); /* so process doesn't go away */
902 /* skip system processes and ones being created or going away */
903 if (p->p_stat == SIDL || p->p_stat == SZOMB ||
904 (p->p_flag & (SSYS | SEXITING | SEXITLWPS))) {
905 mutex_exit(&p->p_lock);
906 continue;
909 mutex_enter(&p->p_crlock);
910 crhold(cr = p->p_cred);
911 mutex_exit(&p->p_crlock);
912 ainfo = crgetauinfo(cr);
913 if (ainfo == NULL) {
914 mutex_exit(&p->p_lock);
915 crfree(cr);
916 continue;
919 if (ainfo->ai_auid == STRUCT_FGET(user_info, ai_auid)) {
920 au_mask_t mask;
921 int err;
924 * Here's a process which matches the specified auid.
925 * If its mask doesn't already match the new mask,
926 * save the new mask in the pad, to be picked up
927 * next syscall.
929 mask = STRUCT_FGET(user_info, ai_mask);
930 err = bcmp(&mask, &ainfo->ai_mask, sizeof (au_mask_t));
931 crfree(cr);
932 if (err != 0) {
933 struct p_audit_data *pad = P2A(p);
934 ASSERT(pad != NULL);
936 mutex_enter(&(pad->pad_lock));
937 pad->pad_flags |= PAD_SETMASK;
938 pad->pad_newmask = mask;
939 mutex_exit(&(pad->pad_lock));
942 * No need to call set_proc_pre_sys(), since
943 * t_pre_sys is ALWAYS on when audit is
944 * enabled...due to syscall auditing.
947 } else {
948 crfree(cr);
950 mutex_exit(&p->p_lock);
952 mutex_exit(&pidlock);
954 return (0);
957 static int
958 setsmask(caddr_t data)
960 STRUCT_DECL(auditinfo, user_info);
961 struct proc *p;
962 const auditinfo_addr_t *ainfo;
963 model_t model;
965 /* setsmask not applicable in non-global zones without perzone policy */
966 if (!(audit_policy & AUDIT_PERZONE) && (!INGLOBALZONE(curproc)))
967 return (EINVAL);
969 model = get_udatamodel();
970 STRUCT_INIT(user_info, model);
972 if (copyin(data, STRUCT_BUF(user_info), STRUCT_SIZE(user_info)))
973 return (EFAULT);
975 mutex_enter(&pidlock); /* lock the process queue against updates */
976 for (p = practive; p != NULL; p = p->p_next) {
977 cred_t *cr;
979 /* if in non-global zone only modify processes in same zone */
980 if (!HASZONEACCESS(curproc, p->p_zone->zone_id))
981 continue;
983 mutex_enter(&p->p_lock); /* so process doesn't go away */
985 /* skip system processes and ones being created or going away */
986 if (p->p_stat == SIDL || p->p_stat == SZOMB ||
987 (p->p_flag & (SSYS | SEXITING | SEXITLWPS))) {
988 mutex_exit(&p->p_lock);
989 continue;
992 mutex_enter(&p->p_crlock);
993 crhold(cr = p->p_cred);
994 mutex_exit(&p->p_crlock);
995 ainfo = crgetauinfo(cr);
996 if (ainfo == NULL) {
997 mutex_exit(&p->p_lock);
998 crfree(cr);
999 continue;
1002 if (ainfo->ai_asid == STRUCT_FGET(user_info, ai_asid)) {
1003 au_mask_t mask;
1004 int err;
1007 * Here's a process which matches the specified asid.
1008 * If its mask doesn't already match the new mask,
1009 * save the new mask in the pad, to be picked up
1010 * next syscall.
1012 mask = STRUCT_FGET(user_info, ai_mask);
1013 err = bcmp(&mask, &ainfo->ai_mask, sizeof (au_mask_t));
1014 crfree(cr);
1015 if (err != 0) {
1016 struct p_audit_data *pad = P2A(p);
1017 ASSERT(pad != NULL);
1019 mutex_enter(&(pad->pad_lock));
1020 pad->pad_flags |= PAD_SETMASK;
1021 pad->pad_newmask = mask;
1022 mutex_exit(&(pad->pad_lock));
1025 * No need to call set_proc_pre_sys(), since
1026 * t_pre_sys is ALWAYS on when audit is
1027 * enabled...due to syscall auditing.
1030 } else {
1031 crfree(cr);
1033 mutex_exit(&p->p_lock);
1035 mutex_exit(&pidlock);
1037 return (0);
1041 * Get the current audit state of the system
1043 static int
1044 getcond(caddr_t data)
1046 au_kcontext_t *kctx = GET_KCTX_PZ;
1048 if (copyout(&(kctx->auk_auditstate), data, sizeof (int)))
1049 return (EFAULT);
1051 return (0);
1055 * Set the current audit state of the system to on (AUC_AUDITING) or
1056 * off (AUC_NOAUDIT).
1058 /* ARGSUSED */
1059 static int
1060 setcond(caddr_t data)
1062 int auditstate;
1063 au_kcontext_t *kctx;
1065 if (!(audit_policy & AUDIT_PERZONE) && (!INGLOBALZONE(curproc)))
1066 return (EINVAL);
1068 kctx = GET_KCTX_NGZ;
1070 if (copyin(data, &auditstate, sizeof (int)))
1071 return (EFAULT);
1073 switch (auditstate) {
1074 case AUC_AUDITING: /* Turn auditing on */
1075 if (audit_active == C2AUDIT_UNLOADED)
1076 audit_init_module();
1077 kctx->auk_auditstate = AUC_AUDITING;
1078 if (!(audit_policy & AUDIT_PERZONE) && INGLOBALZONE(curproc))
1079 set_all_zone_usr_proc_sys(ALL_ZONES);
1080 else
1081 set_all_zone_usr_proc_sys(curproc->p_zone->zone_id);
1082 break;
1084 case AUC_NOAUDIT: /* Turn auditing off */
1085 if (kctx->auk_auditstate == AUC_NOAUDIT)
1086 break;
1087 kctx->auk_auditstate = AUC_NOAUDIT;
1089 /* clear out the audit queue */
1091 mutex_enter(&(kctx->auk_queue.lock));
1092 if (kctx->auk_queue.wt_block)
1093 cv_broadcast(&(kctx->auk_queue.write_cv));
1095 /* unblock au_output_thread */
1096 cv_broadcast(&(kctx->auk_queue.read_cv));
1098 mutex_exit(&(kctx->auk_queue.lock));
1099 break;
1101 default:
1102 return (EINVAL);
1105 return (0);
1108 static int
1109 getclass(caddr_t data)
1111 au_evclass_map_t event;
1112 au_kcontext_t *kctx = GET_KCTX_PZ;
1114 if (copyin(data, &event, sizeof (au_evclass_map_t)))
1115 return (EFAULT);
1117 if (event.ec_number > MAX_KEVENTS)
1118 return (EINVAL);
1120 event.ec_class = kctx->auk_ets[event.ec_number];
1122 if (copyout(&event, data, sizeof (au_evclass_map_t)))
1123 return (EFAULT);
1125 return (0);
1128 static int
1129 setclass(caddr_t data)
1131 au_evclass_map_t event;
1132 au_kcontext_t *kctx;
1134 if (!(audit_policy & AUDIT_PERZONE) && !INGLOBALZONE(curproc))
1135 return (EINVAL);
1137 kctx = GET_KCTX_NGZ;
1139 if (copyin(data, &event, sizeof (au_evclass_map_t)))
1140 return (EFAULT);
1142 if (event.ec_number > MAX_KEVENTS)
1143 return (EINVAL);
1145 kctx->auk_ets[event.ec_number] = event.ec_class;
1147 return (0);
1150 static int
1151 getpinfo(caddr_t data)
1153 STRUCT_DECL(auditpinfo, apinfo);
1154 proc_t *proc;
1155 const auditinfo_addr_t *ainfo;
1156 model_t model;
1157 cred_t *cr, *newcred;
1159 model = get_udatamodel();
1160 STRUCT_INIT(apinfo, model);
1162 if (copyin(data, STRUCT_BUF(apinfo), STRUCT_SIZE(apinfo)))
1163 return (EFAULT);
1165 newcred = cralloc();
1167 mutex_enter(&pidlock);
1168 if ((proc = prfind(STRUCT_FGET(apinfo, ap_pid))) == NULL) {
1169 mutex_exit(&pidlock);
1170 crfree(newcred);
1171 return (ESRCH); /* no such process */
1173 mutex_enter(&proc->p_lock); /* so process doesn't go away */
1174 mutex_exit(&pidlock);
1176 audit_update_context(proc, newcred); /* make sure it's up-to-date */
1178 mutex_enter(&proc->p_crlock);
1179 crhold(cr = proc->p_cred);
1180 mutex_exit(&proc->p_crlock);
1181 mutex_exit(&proc->p_lock);
1183 ainfo = crgetauinfo(cr);
1184 if (ainfo == NULL) {
1185 crfree(cr);
1186 return (EINVAL);
1189 /* designated process has an ipv6 address? */
1190 if (ainfo->ai_termid.at_type == AU_IPv6) {
1191 crfree(cr);
1192 return (EOVERFLOW);
1195 STRUCT_FSET(apinfo, ap_auid, ainfo->ai_auid);
1196 STRUCT_FSET(apinfo, ap_asid, ainfo->ai_asid);
1197 #ifdef _LP64
1198 if (model == DATAMODEL_ILP32) {
1199 dev32_t dev;
1200 /* convert internal 64 bit form to 32 bit version */
1201 if (cmpldev(&dev, ainfo->ai_termid.at_port) == 0) {
1202 crfree(cr);
1203 return (EOVERFLOW);
1205 STRUCT_FSET(apinfo, ap_termid.port, dev);
1206 } else
1207 STRUCT_FSET(apinfo, ap_termid.port, ainfo->ai_termid.at_port);
1208 #else
1209 STRUCT_FSET(apinfo, ap_termid.port, ainfo->ai_termid.at_port);
1210 #endif
1211 STRUCT_FSET(apinfo, ap_termid.machine, ainfo->ai_termid.at_addr[0]);
1212 STRUCT_FSET(apinfo, ap_mask, ainfo->ai_mask);
1214 crfree(cr);
1216 if (copyout(STRUCT_BUF(apinfo), data, STRUCT_SIZE(apinfo)))
1217 return (EFAULT);
1219 return (0);
1222 static int
1223 getpinfo_addr(caddr_t data, int len)
1225 STRUCT_DECL(auditpinfo_addr, apinfo);
1226 proc_t *proc;
1227 const auditinfo_addr_t *ainfo;
1228 model_t model;
1229 cred_t *cr, *newcred;
1231 model = get_udatamodel();
1232 STRUCT_INIT(apinfo, model);
1234 if (len < STRUCT_SIZE(apinfo))
1235 return (EOVERFLOW);
1237 if (copyin(data, STRUCT_BUF(apinfo), STRUCT_SIZE(apinfo)))
1238 return (EFAULT);
1240 newcred = cralloc();
1242 mutex_enter(&pidlock);
1243 if ((proc = prfind(STRUCT_FGET(apinfo, ap_pid))) == NULL) {
1244 mutex_exit(&pidlock);
1245 crfree(newcred);
1246 return (ESRCH);
1248 mutex_enter(&proc->p_lock); /* so process doesn't go away */
1249 mutex_exit(&pidlock);
1251 audit_update_context(proc, newcred); /* make sure it's up-to-date */
1253 mutex_enter(&proc->p_crlock);
1254 crhold(cr = proc->p_cred);
1255 mutex_exit(&proc->p_crlock);
1256 mutex_exit(&proc->p_lock);
1258 ainfo = crgetauinfo(cr);
1259 if (ainfo == NULL) {
1260 crfree(cr);
1261 return (EINVAL);
1264 STRUCT_FSET(apinfo, ap_auid, ainfo->ai_auid);
1265 STRUCT_FSET(apinfo, ap_asid, ainfo->ai_asid);
1266 #ifdef _LP64
1267 if (model == DATAMODEL_ILP32) {
1268 dev32_t dev;
1269 /* convert internal 64 bit form to 32 bit version */
1270 if (cmpldev(&dev, ainfo->ai_termid.at_port) == 0) {
1271 crfree(cr);
1272 return (EOVERFLOW);
1274 STRUCT_FSET(apinfo, ap_termid.at_port, dev);
1275 } else
1276 STRUCT_FSET(apinfo, ap_termid.at_port,
1277 ainfo->ai_termid.at_port);
1278 #else
1279 STRUCT_FSET(apinfo, ap_termid.at_port, ainfo->ai_termid.at_port);
1280 #endif
1281 STRUCT_FSET(apinfo, ap_termid.at_type, ainfo->ai_termid.at_type);
1282 STRUCT_FSET(apinfo, ap_termid.at_addr[0], ainfo->ai_termid.at_addr[0]);
1283 STRUCT_FSET(apinfo, ap_termid.at_addr[1], ainfo->ai_termid.at_addr[1]);
1284 STRUCT_FSET(apinfo, ap_termid.at_addr[2], ainfo->ai_termid.at_addr[2]);
1285 STRUCT_FSET(apinfo, ap_termid.at_addr[3], ainfo->ai_termid.at_addr[3]);
1286 STRUCT_FSET(apinfo, ap_mask, ainfo->ai_mask);
1288 crfree(cr);
1290 if (copyout(STRUCT_BUF(apinfo), data, STRUCT_SIZE(apinfo)))
1291 return (EFAULT);
1293 return (0);
1296 static int
1297 setpmask(caddr_t data)
1299 STRUCT_DECL(auditpinfo, apinfo);
1300 proc_t *proc;
1301 cred_t *newcred;
1302 auditinfo_addr_t *ainfo;
1303 struct p_audit_data *pad;
1305 model_t model;
1307 model = get_udatamodel();
1308 STRUCT_INIT(apinfo, model);
1310 if (copyin(data, STRUCT_BUF(apinfo), STRUCT_SIZE(apinfo)))
1311 return (EFAULT);
1313 mutex_enter(&pidlock);
1314 if ((proc = prfind(STRUCT_FGET(apinfo, ap_pid))) == NULL) {
1315 mutex_exit(&pidlock);
1316 return (ESRCH);
1318 mutex_enter(&proc->p_lock); /* so process doesn't go away */
1319 mutex_exit(&pidlock);
1321 newcred = cralloc();
1322 if ((ainfo = crgetauinfo_modifiable(newcred)) == NULL) {
1323 mutex_exit(&proc->p_lock);
1324 crfree(newcred);
1325 return (EINVAL);
1328 mutex_enter(&proc->p_crlock);
1329 crcopy_to(proc->p_cred, newcred);
1330 proc->p_cred = newcred;
1332 ainfo->ai_mask = STRUCT_FGET(apinfo, ap_mask);
1335 * Unlock. No need to broadcast changes via set_proc_pre_sys(),
1336 * since t_pre_sys is ALWAYS on when audit is enabled... due to
1337 * syscall auditing.
1339 crfree(newcred);
1340 mutex_exit(&proc->p_crlock);
1342 /* Reset flag for any previous pending mask change; this supercedes */
1343 pad = P2A(proc);
1344 ASSERT(pad != NULL);
1345 mutex_enter(&(pad->pad_lock));
1346 pad->pad_flags &= ~PAD_SETMASK;
1347 mutex_exit(&(pad->pad_lock));
1349 mutex_exit(&proc->p_lock);
1351 return (0);
1355 * The out of control system call
1356 * This is audit kitchen sink aka auditadm, aka auditon
1359 auditctl(
1360 int cmd,
1361 caddr_t data,
1362 int length)
1364 int result;
1366 switch (cmd) {
1367 case A_GETAMASK:
1368 case A_GETCOND:
1369 case A_GETCAR:
1370 case A_GETCLASS:
1371 case A_GETCWD:
1372 case A_GETKAUDIT:
1373 case A_GETKMASK:
1374 case A_GETPINFO:
1375 case A_GETPINFO_ADDR:
1376 case A_GETPOLICY:
1377 case A_GETQCTRL:
1378 case A_GETSTAT:
1379 if (secpolicy_audit_getattr(CRED(), B_FALSE) != 0)
1380 return (EPERM);
1381 break;
1382 default:
1383 if (secpolicy_audit_config(CRED()) != 0)
1384 return (EPERM);
1385 break;
1388 switch (cmd) {
1389 case A_GETPOLICY:
1390 result = getpolicy(data);
1391 break;
1392 case A_SETPOLICY:
1393 result = setpolicy(data);
1394 break;
1395 case A_GETAMASK:
1396 result = getamask(data);
1397 break;
1398 case A_SETAMASK:
1399 result = setamask(data);
1400 break;
1401 case A_GETKMASK:
1402 result = getkmask(data);
1403 break;
1404 case A_SETKMASK:
1405 result = setkmask(data);
1406 break;
1407 case A_GETKAUDIT:
1408 result = getkaudit(data, length);
1409 break;
1410 case A_SETKAUDIT:
1411 result = setkaudit(data, length);
1412 break;
1413 case A_GETQCTRL:
1414 result = getqctrl(data);
1415 break;
1416 case A_SETQCTRL:
1417 result = setqctrl(data);
1418 break;
1419 case A_GETCWD:
1420 result = getcwd(data, length);
1421 break;
1422 case A_GETCAR:
1423 result = getcar(data, length);
1424 break;
1425 case A_GETSTAT:
1426 result = getstat(data);
1427 break;
1428 case A_SETSTAT:
1429 result = setstat(data);
1430 break;
1431 case A_SETUMASK:
1432 result = setumask(data);
1433 break;
1434 case A_SETSMASK:
1435 result = setsmask(data);
1436 break;
1437 case A_GETCOND:
1438 result = getcond(data);
1439 break;
1440 case A_SETCOND:
1441 result = setcond(data);
1442 break;
1443 case A_GETCLASS:
1444 result = getclass(data);
1445 break;
1446 case A_SETCLASS:
1447 result = setclass(data);
1448 break;
1449 case A_GETPINFO:
1450 result = getpinfo(data);
1451 break;
1452 case A_GETPINFO_ADDR:
1453 result = getpinfo_addr(data, length);
1454 break;
1455 case A_SETPMASK:
1456 result = setpmask(data);
1457 break;
1458 default:
1459 result = EINVAL;
1460 break;
1462 return (result);