geniconvtbl: small cstyle fix
[unleashed.git] / kernel / syscall / auditsys.c
blob61116dffd28b4eeb9208f39d2c54048f856cc5ce
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 default:
83 if (audit_active == C2AUDIT_LOADED) {
84 result = EINVAL;
85 break;
87 /* Return a different error when not privileged */
88 err = secpolicy_audit_config(CRED());
89 if (err == 0)
90 return (EINVAL);
91 else
92 return (err);
94 rvp->r_vals = result;
95 return (result);
99 * Return the audit user ID for the current process. Currently only
100 * the privileged processes may see the audit id. That may change.
101 * If copyout is unsucessful return EFAULT.
104 getauid(caddr_t auid_p)
106 const auditinfo_addr_t *ainfo;
108 if (secpolicy_audit_getattr(CRED(), B_FALSE) != 0)
109 return (EPERM);
111 ainfo = crgetauinfo(CRED());
112 if (ainfo == NULL)
113 return (EINVAL);
115 if (copyout(&ainfo->ai_auid, auid_p, sizeof (au_id_t)))
116 return (EFAULT);
118 return (0);
122 * Set the audit userid, for a process. This can only be changed by
123 * privileged processes. The audit userid is inherited across forks & execs.
124 * Passed in is a pointer to the au_id_t; if copyin unsuccessful return EFAULT.
127 setauid(caddr_t auid_p)
129 proc_t *p;
130 au_id_t auid;
131 cred_t *newcred;
132 auditinfo_addr_t *auinfo;
134 if (secpolicy_audit_config(CRED()) != 0)
135 return (EPERM);
137 if (copyin(auid_p, &auid, sizeof (au_id_t))) {
138 return (EFAULT);
141 newcred = cralloc();
142 if ((auinfo = crgetauinfo_modifiable(newcred)) == NULL) {
143 crfree(newcred);
144 return (EINVAL);
147 /* grab p_crlock and switch to new cred */
148 p = curproc;
149 mutex_enter(&p->p_crlock);
150 crcopy_to(p->p_cred, newcred);
151 p->p_cred = newcred;
153 auinfo->ai_auid = auid; /* update the auid */
155 /* unlock and broadcast the cred changes */
156 mutex_exit(&p->p_crlock);
157 crset(p, newcred);
159 return (0);
163 * Get the audit state information from the current process.
164 * Return EFAULT if copyout fails.
167 getaudit(caddr_t info_p)
169 STRUCT_DECL(auditinfo, info);
170 const auditinfo_addr_t *ainfo;
171 model_t model;
173 if (secpolicy_audit_getattr(CRED(), B_FALSE) != 0)
174 return (EPERM);
176 model = get_udatamodel();
177 STRUCT_INIT(info, model);
179 ainfo = crgetauinfo(CRED());
180 if (ainfo == NULL)
181 return (EINVAL);
183 /* trying to read a process with an IPv6 address? */
184 if (ainfo->ai_termid.at_type == AU_IPv6)
185 return (EOVERFLOW);
187 STRUCT_FSET(info, ai_auid, ainfo->ai_auid);
188 STRUCT_FSET(info, ai_mask, ainfo->ai_mask);
189 #ifdef _LP64
190 if (model == DATAMODEL_ILP32) {
191 dev32_t dev;
192 /* convert internal 64 bit form to 32 bit version */
193 if (cmpldev(&dev, ainfo->ai_termid.at_port) == 0) {
194 return (EOVERFLOW);
196 STRUCT_FSET(info, ai_termid.port, dev);
197 } else
198 STRUCT_FSET(info, ai_termid.port, ainfo->ai_termid.at_port);
199 #else
200 STRUCT_FSET(info, ai_termid.port, ainfo->ai_termid.at_port);
201 #endif
202 STRUCT_FSET(info, ai_termid.machine, ainfo->ai_termid.at_addr[0]);
203 STRUCT_FSET(info, ai_asid, ainfo->ai_asid);
205 if (copyout(STRUCT_BUF(info), info_p, STRUCT_SIZE(info)))
206 return (EFAULT);
208 return (0);
212 * Get the audit state information from the current process.
213 * Return EFAULT if copyout fails.
216 getaudit_addr(caddr_t info_p, int len)
218 STRUCT_DECL(auditinfo_addr, info);
219 const auditinfo_addr_t *ainfo;
220 model_t model;
222 if (secpolicy_audit_getattr(CRED(), B_FALSE) != 0)
223 return (EPERM);
225 model = get_udatamodel();
226 STRUCT_INIT(info, model);
228 if (len < STRUCT_SIZE(info))
229 return (EOVERFLOW);
231 ainfo = crgetauinfo(CRED());
233 if (ainfo == NULL)
234 return (EINVAL);
236 STRUCT_FSET(info, ai_auid, ainfo->ai_auid);
237 STRUCT_FSET(info, ai_mask, ainfo->ai_mask);
238 #ifdef _LP64
239 if (model == DATAMODEL_ILP32) {
240 dev32_t dev;
241 /* convert internal 64 bit form to 32 bit version */
242 if (cmpldev(&dev, ainfo->ai_termid.at_port) == 0) {
243 return (EOVERFLOW);
245 STRUCT_FSET(info, ai_termid.at_port, dev);
246 } else
247 STRUCT_FSET(info, ai_termid.at_port, ainfo->ai_termid.at_port);
248 #else
249 STRUCT_FSET(info, ai_termid.at_port, ainfo->ai_termid.at_port);
250 #endif
251 STRUCT_FSET(info, ai_termid.at_type, ainfo->ai_termid.at_type);
252 STRUCT_FSET(info, ai_termid.at_addr[0], ainfo->ai_termid.at_addr[0]);
253 STRUCT_FSET(info, ai_termid.at_addr[1], ainfo->ai_termid.at_addr[1]);
254 STRUCT_FSET(info, ai_termid.at_addr[2], ainfo->ai_termid.at_addr[2]);
255 STRUCT_FSET(info, ai_termid.at_addr[3], ainfo->ai_termid.at_addr[3]);
256 STRUCT_FSET(info, ai_asid, ainfo->ai_asid);
258 if (copyout(STRUCT_BUF(info), info_p, STRUCT_SIZE(info)))
259 return (EFAULT);
261 return (0);
265 * Set the audit state information for the current process.
266 * Return EFAULT if copyout fails.
269 setaudit(caddr_t info_p)
271 STRUCT_DECL(auditinfo, info);
272 proc_t *p;
273 cred_t *newcred;
274 model_t model;
275 auditinfo_addr_t *ainfo;
277 if (secpolicy_audit_config(CRED()) != 0)
278 return (EPERM);
280 model = get_udatamodel();
281 STRUCT_INIT(info, model);
283 if (copyin(info_p, STRUCT_BUF(info), STRUCT_SIZE(info)))
284 return (EFAULT);
286 newcred = cralloc();
287 if ((ainfo = crgetauinfo_modifiable(newcred)) == NULL) {
288 crfree(newcred);
289 return (EINVAL);
292 /* grab p_crlock and switch to new cred */
293 p = curproc;
294 mutex_enter(&p->p_crlock);
295 crcopy_to(p->p_cred, newcred);
296 p->p_cred = newcred;
298 /* Set audit mask, id, termid and session id as specified */
299 ainfo->ai_auid = STRUCT_FGET(info, ai_auid);
300 #ifdef _LP64
301 /* only convert to 64 bit if coming from a 32 bit binary */
302 if (model == DATAMODEL_ILP32)
303 ainfo->ai_termid.at_port =
304 DEVEXPL(STRUCT_FGET(info, ai_termid.port));
305 else
306 ainfo->ai_termid.at_port = STRUCT_FGET(info, ai_termid.port);
307 #else
308 ainfo->ai_termid.at_port = STRUCT_FGET(info, ai_termid.port);
309 #endif
310 ainfo->ai_termid.at_type = AU_IPv4;
311 ainfo->ai_termid.at_addr[0] = STRUCT_FGET(info, ai_termid.machine);
312 ainfo->ai_asid = STRUCT_FGET(info, ai_asid);
313 ainfo->ai_mask = STRUCT_FGET(info, ai_mask);
315 /* unlock and broadcast the cred changes */
316 mutex_exit(&p->p_crlock);
317 crset(p, newcred);
319 return (0);
323 * Set the audit state information for the current process.
324 * Return EFAULT if copyin fails.
327 setaudit_addr(caddr_t info_p, int len)
329 STRUCT_DECL(auditinfo_addr, info);
330 proc_t *p;
331 cred_t *newcred;
332 model_t model;
333 int i;
334 int type;
335 auditinfo_addr_t *ainfo;
337 if (secpolicy_audit_config(CRED()) != 0)
338 return (EPERM);
340 model = get_udatamodel();
341 STRUCT_INIT(info, model);
343 if (len < STRUCT_SIZE(info))
344 return (EOVERFLOW);
346 if (copyin(info_p, STRUCT_BUF(info), STRUCT_SIZE(info)))
347 return (EFAULT);
349 type = STRUCT_FGET(info, ai_termid.at_type);
350 if ((type != AU_IPv4) && (type != AU_IPv6))
351 return (EINVAL);
353 newcred = cralloc();
354 if ((ainfo = crgetauinfo_modifiable(newcred)) == NULL) {
355 crfree(newcred);
356 return (EINVAL);
359 /* grab p_crlock and switch to new cred */
360 p = curproc;
361 mutex_enter(&p->p_crlock);
362 crcopy_to(p->p_cred, newcred);
363 p->p_cred = newcred;
365 /* Set audit mask, id, termid and session id as specified */
366 ainfo->ai_auid = STRUCT_FGET(info, ai_auid);
367 ainfo->ai_mask = STRUCT_FGET(info, ai_mask);
368 #ifdef _LP64
369 /* only convert to 64 bit if coming from a 32 bit binary */
370 if (model == DATAMODEL_ILP32)
371 ainfo->ai_termid.at_port =
372 DEVEXPL(STRUCT_FGET(info, ai_termid.at_port));
373 else
374 ainfo->ai_termid.at_port = STRUCT_FGET(info, ai_termid.at_port);
375 #else
376 ainfo->ai_termid.at_port = STRUCT_FGET(info, ai_termid.at_port);
377 #endif
378 ainfo->ai_termid.at_type = type;
379 bzero(&ainfo->ai_termid.at_addr[0], sizeof (ainfo->ai_termid.at_addr));
380 for (i = 0; i < (type/sizeof (int)); i++)
381 ainfo->ai_termid.at_addr[i] =
382 STRUCT_FGET(info, ai_termid.at_addr[i]);
384 if (ainfo->ai_termid.at_type == AU_IPv6 &&
385 IN6_IS_ADDR_V4MAPPED(((in6_addr_t *)ainfo->ai_termid.at_addr))) {
386 ainfo->ai_termid.at_type = AU_IPv4;
387 ainfo->ai_termid.at_addr[0] = ainfo->ai_termid.at_addr[3];
388 ainfo->ai_termid.at_addr[1] = 0;
389 ainfo->ai_termid.at_addr[2] = 0;
390 ainfo->ai_termid.at_addr[3] = 0;
393 ainfo->ai_asid = STRUCT_FGET(info, ai_asid);
395 /* unlock and broadcast the cred changes */
396 mutex_exit(&p->p_crlock);
397 crset(p, newcred);
399 return (0);
403 * Get the global policy flag
405 static int
406 getpolicy(caddr_t data)
408 uint32_t policy;
409 au_kcontext_t *kctx = GET_KCTX_PZ;
411 policy = audit_policy | kctx->auk_policy;
413 if (copyout(&policy, data, sizeof (policy)))
414 return (EFAULT);
415 return (0);
419 * Set the global and local policy flags
421 * The global flags only make sense from the global zone;
422 * the local flags depend on the AUDIT_PERZONE policy:
423 * if the perzone policy is set, then policy is set separately
424 * per zone, else held only in the global zone.
426 * The initial value of a local zone's policy flag is determined
427 * by the value of the global zone's flags at the time the
428 * local zone is created.
430 * While auditconfig(1M) allows setting and unsetting policies one bit
431 * at a time, the mask passed in from auditconfig() is created by a
432 * syscall to getpolicy and then modified based on the auditconfig()
433 * cmd line, so the input policy value is used to replace the existing
434 * policy.
436 static int
437 setpolicy(caddr_t data)
439 uint32_t policy;
440 au_kcontext_t *kctx;
442 if (copyin(data, &policy, sizeof (policy)))
443 return (EFAULT);
445 kctx = GET_KCTX_NGZ;
447 if (INGLOBALZONE(curproc)) {
448 if (policy & ~(AUDIT_GLOBAL | AUDIT_LOCAL))
449 return (EINVAL);
451 audit_policy = policy & AUDIT_GLOBAL;
452 } else {
453 if (!(audit_policy & AUDIT_PERZONE))
454 return (EINVAL);
456 if (policy & ~AUDIT_LOCAL) /* global bits are a no-no */
457 return (EINVAL);
459 kctx->auk_policy = policy & AUDIT_LOCAL;
462 * auk_current_vp is NULL before auditd starts (or during early
463 * auditd starup) or if auditd is halted; in either case,
464 * notification of a policy change is not needed, since auditd
465 * reads policy as it comes up. The error return from au_doormsg()
466 * is ignored to avoid a race condition -- for example if auditd
467 * segv's, the audit state may be "auditing" but the door may
468 * be closed. Returning an error if the door is open makes it
469 * impossible for Greenline to restart auditd.
471 if (kctx->auk_current_vp != NULL)
472 (void) au_doormsg(kctx, AU_DBUF_POLICY, &policy);
475 * Wake up anyone who might have blocked on full audit
476 * partitions. audit daemons need to set AUDIT_FULL when no
477 * space so we can tell if we should start dropping records.
479 mutex_enter(&(kctx->auk_queue.lock));
481 if ((policy & (AUDIT_CNT | AUDIT_SCNT) &&
482 (kctx->auk_queue.cnt >= kctx->auk_queue.hiwater)))
483 cv_broadcast(&(kctx->auk_queue.write_cv));
485 mutex_exit(&(kctx->auk_queue.lock));
487 return (0);
490 static int
491 getamask(caddr_t data)
493 au_kcontext_t *kctx;
495 kctx = GET_KCTX_PZ;
497 if (copyout(&kctx->auk_info.ai_amask, data, sizeof (au_mask_t)))
498 return (EFAULT);
500 return (0);
503 static int
504 setamask(caddr_t data)
506 au_mask_t mask;
507 au_kcontext_t *kctx;
509 if (!(audit_policy & AUDIT_PERZONE) && !INGLOBALZONE(curproc))
510 return (EINVAL);
512 kctx = GET_KCTX_NGZ;
514 if (copyin(data, &mask, sizeof (au_mask_t)))
515 return (EFAULT);
517 kctx->auk_info.ai_amask = mask;
518 return (0);
521 static int
522 getkmask(caddr_t data)
524 au_kcontext_t *kctx;
526 kctx = GET_KCTX_PZ;
528 if (copyout(&kctx->auk_info.ai_namask, data, sizeof (au_mask_t)))
529 return (EFAULT);
530 return (0);
533 static int
534 setkmask(caddr_t data)
536 au_mask_t mask;
537 au_kcontext_t *kctx;
539 if (!(audit_policy & AUDIT_PERZONE) && !INGLOBALZONE(curproc))
540 return (EINVAL);
542 kctx = GET_KCTX_NGZ;
544 if (copyin(data, &mask, sizeof (au_mask_t)))
545 return (EFAULT);
547 kctx->auk_info.ai_namask = mask;
548 return (0);
551 static int
552 getkaudit(caddr_t info_p, int len)
554 STRUCT_DECL(auditinfo_addr, info);
555 model_t model;
556 au_kcontext_t *kctx = GET_KCTX_PZ;
558 model = get_udatamodel();
559 STRUCT_INIT(info, model);
561 if (len < STRUCT_SIZE(info))
562 return (EOVERFLOW);
564 STRUCT_FSET(info, ai_auid, kctx->auk_info.ai_auid);
565 STRUCT_FSET(info, ai_mask, kctx->auk_info.ai_namask);
566 #ifdef _LP64
567 if (model == DATAMODEL_ILP32) {
568 dev32_t dev;
569 /* convert internal 64 bit form to 32 bit version */
570 if (cmpldev(&dev, kctx->auk_info.ai_termid.at_port) == 0) {
571 return (EOVERFLOW);
573 STRUCT_FSET(info, ai_termid.at_port, dev);
574 } else {
575 STRUCT_FSET(info, ai_termid.at_port,
576 kctx->auk_info.ai_termid.at_port);
578 #else
579 STRUCT_FSET(info, ai_termid.at_port,
580 kctx->auk_info.ai_termid.at_port);
581 #endif
582 STRUCT_FSET(info, ai_termid.at_type,
583 kctx->auk_info.ai_termid.at_type);
584 STRUCT_FSET(info, ai_termid.at_addr[0],
585 kctx->auk_info.ai_termid.at_addr[0]);
586 STRUCT_FSET(info, ai_termid.at_addr[1],
587 kctx->auk_info.ai_termid.at_addr[1]);
588 STRUCT_FSET(info, ai_termid.at_addr[2],
589 kctx->auk_info.ai_termid.at_addr[2]);
590 STRUCT_FSET(info, ai_termid.at_addr[3],
591 kctx->auk_info.ai_termid.at_addr[3]);
592 STRUCT_FSET(info, ai_asid, kctx->auk_info.ai_asid);
594 if (copyout(STRUCT_BUF(info), info_p, STRUCT_SIZE(info)))
595 return (EFAULT);
597 return (0);
601 * the host address for AUDIT_PERZONE == 0 is that of the global
602 * zone and for local zones it is of the current zone.
604 static int
605 setkaudit(caddr_t info_p, int len)
607 STRUCT_DECL(auditinfo_addr, info);
608 model_t model;
609 au_kcontext_t *kctx;
611 if (!(audit_policy & AUDIT_PERZONE) && !INGLOBALZONE(curproc))
612 return (EINVAL);
614 kctx = GET_KCTX_NGZ;
616 model = get_udatamodel();
617 STRUCT_INIT(info, model);
619 if (len < STRUCT_SIZE(info))
620 return (EOVERFLOW);
622 if (copyin(info_p, STRUCT_BUF(info), STRUCT_SIZE(info)))
623 return (EFAULT);
625 if ((STRUCT_FGET(info, ai_termid.at_type) != AU_IPv4) &&
626 (STRUCT_FGET(info, ai_termid.at_type) != AU_IPv6))
627 return (EINVAL);
629 /* Set audit mask, termid and session id as specified */
630 kctx->auk_info.ai_auid = STRUCT_FGET(info, ai_auid);
631 kctx->auk_info.ai_namask = STRUCT_FGET(info, ai_mask);
632 #ifdef _LP64
633 /* only convert to 64 bit if coming from a 32 bit binary */
634 if (model == DATAMODEL_ILP32)
635 kctx->auk_info.ai_termid.at_port =
636 DEVEXPL(STRUCT_FGET(info, ai_termid.at_port));
637 else
638 kctx->auk_info.ai_termid.at_port =
639 STRUCT_FGET(info, ai_termid.at_port);
640 #else
641 kctx->auk_info.ai_termid.at_port = STRUCT_FGET(info, ai_termid.at_port);
642 #endif
643 kctx->auk_info.ai_termid.at_type = STRUCT_FGET(info, ai_termid.at_type);
644 bzero(&kctx->auk_info.ai_termid.at_addr[0],
645 sizeof (kctx->auk_info.ai_termid.at_addr));
646 kctx->auk_info.ai_termid.at_addr[0] =
647 STRUCT_FGET(info, ai_termid.at_addr[0]);
648 kctx->auk_info.ai_termid.at_addr[1] =
649 STRUCT_FGET(info, ai_termid.at_addr[1]);
650 kctx->auk_info.ai_termid.at_addr[2] =
651 STRUCT_FGET(info, ai_termid.at_addr[2]);
652 kctx->auk_info.ai_termid.at_addr[3] =
653 STRUCT_FGET(info, ai_termid.at_addr[3]);
654 kctx->auk_info.ai_asid = STRUCT_FGET(info, ai_asid);
656 if (kctx->auk_info.ai_termid.at_type == AU_IPv6 &&
657 IN6_IS_ADDR_V4MAPPED(
658 ((in6_addr_t *)kctx->auk_info.ai_termid.at_addr))) {
659 kctx->auk_info.ai_termid.at_type = AU_IPv4;
660 kctx->auk_info.ai_termid.at_addr[0] =
661 kctx->auk_info.ai_termid.at_addr[3];
662 kctx->auk_info.ai_termid.at_addr[1] = 0;
663 kctx->auk_info.ai_termid.at_addr[2] = 0;
664 kctx->auk_info.ai_termid.at_addr[3] = 0;
666 if (kctx->auk_info.ai_termid.at_type == AU_IPv6)
667 kctx->auk_hostaddr_valid = IN6_IS_ADDR_UNSPECIFIED(
668 (in6_addr_t *)kctx->auk_info.ai_termid.at_addr) ? 0 : 1;
669 else
670 kctx->auk_hostaddr_valid =
671 (kctx->auk_info.ai_termid.at_addr[0] ==
672 htonl(INADDR_ANY)) ? 0 : 1;
674 return (0);
677 static int
678 getqctrl(caddr_t data)
680 au_kcontext_t *kctx = GET_KCTX_PZ;
681 STRUCT_DECL(au_qctrl, qctrl);
682 STRUCT_INIT(qctrl, get_udatamodel());
684 mutex_enter(&(kctx->auk_queue.lock));
685 STRUCT_FSET(qctrl, aq_hiwater, kctx->auk_queue.hiwater);
686 STRUCT_FSET(qctrl, aq_lowater, kctx->auk_queue.lowater);
687 STRUCT_FSET(qctrl, aq_bufsz, kctx->auk_queue.bufsz);
688 STRUCT_FSET(qctrl, aq_delay, kctx->auk_queue.delay);
689 mutex_exit(&(kctx->auk_queue.lock));
691 if (copyout(STRUCT_BUF(qctrl), data, STRUCT_SIZE(qctrl)))
692 return (EFAULT);
694 return (0);
697 static int
698 setqctrl(caddr_t data)
700 au_kcontext_t *kctx;
701 struct au_qctrl qctrl_tmp;
702 STRUCT_DECL(au_qctrl, qctrl);
703 STRUCT_INIT(qctrl, get_udatamodel());
705 if (!(audit_policy & AUDIT_PERZONE) && !INGLOBALZONE(curproc))
706 return (EINVAL);
707 kctx = GET_KCTX_NGZ;
709 if (copyin(data, STRUCT_BUF(qctrl), STRUCT_SIZE(qctrl)))
710 return (EFAULT);
712 qctrl_tmp.aq_hiwater = (size_t)STRUCT_FGET(qctrl, aq_hiwater);
713 qctrl_tmp.aq_lowater = (size_t)STRUCT_FGET(qctrl, aq_lowater);
714 qctrl_tmp.aq_bufsz = (size_t)STRUCT_FGET(qctrl, aq_bufsz);
715 qctrl_tmp.aq_delay = (clock_t)STRUCT_FGET(qctrl, aq_delay);
717 /* enforce sane values */
719 if (qctrl_tmp.aq_hiwater <= qctrl_tmp.aq_lowater)
720 return (EINVAL);
722 if (qctrl_tmp.aq_hiwater < AQ_LOWATER)
723 return (EINVAL);
725 if (qctrl_tmp.aq_hiwater > AQ_MAXHIGH)
726 return (EINVAL);
728 if (qctrl_tmp.aq_bufsz < AQ_BUFSZ)
729 return (EINVAL);
731 if (qctrl_tmp.aq_bufsz > AQ_MAXBUFSZ)
732 return (EINVAL);
734 if (qctrl_tmp.aq_delay == 0)
735 return (EINVAL);
737 if (qctrl_tmp.aq_delay > AQ_MAXDELAY)
738 return (EINVAL);
740 /* update everything at once so things are consistant */
741 mutex_enter(&(kctx->auk_queue.lock));
742 kctx->auk_queue.hiwater = qctrl_tmp.aq_hiwater;
743 kctx->auk_queue.lowater = qctrl_tmp.aq_lowater;
744 kctx->auk_queue.bufsz = qctrl_tmp.aq_bufsz;
745 kctx->auk_queue.delay = qctrl_tmp.aq_delay;
747 if (kctx->auk_queue.rd_block &&
748 kctx->auk_queue.cnt > kctx->auk_queue.lowater)
749 cv_broadcast(&(kctx->auk_queue.read_cv));
751 if (kctx->auk_queue.wt_block &&
752 kctx->auk_queue.cnt < kctx->auk_queue.hiwater)
753 cv_broadcast(&(kctx->auk_queue.write_cv));
755 mutex_exit(&(kctx->auk_queue.lock));
757 return (0);
760 static int
761 getcwd(caddr_t data, int length)
763 struct p_audit_data *pad;
764 struct audit_path *app;
765 int pathlen;
767 pad = P2A(curproc);
768 ASSERT(pad != NULL);
770 mutex_enter(&(pad->pad_lock));
771 app = pad->pad_cwd;
772 au_pathhold(app);
773 mutex_exit(&(pad->pad_lock));
775 pathlen = app->audp_sect[1] - app->audp_sect[0];
776 if (pathlen > length) {
777 au_pathrele(app);
778 return (E2BIG);
781 if (copyout(app->audp_sect[0], data, pathlen)) {
782 au_pathrele(app);
783 return (EFAULT);
786 au_pathrele(app);
787 return (0);
790 static int
791 getcar(caddr_t data, int length)
793 struct p_audit_data *pad;
794 struct audit_path *app;
795 int pathlen;
797 pad = P2A(curproc);
798 ASSERT(pad != NULL);
800 mutex_enter(&(pad->pad_lock));
801 app = pad->pad_root;
802 au_pathhold(app);
803 mutex_exit(&(pad->pad_lock));
805 pathlen = app->audp_sect[1] - app->audp_sect[0];
806 if (pathlen > length) {
807 au_pathrele(app);
808 return (E2BIG);
811 if (copyout(app->audp_sect[0], data, pathlen)) {
812 au_pathrele(app);
813 return (EFAULT);
816 au_pathrele(app);
817 return (0);
820 static int
821 getstat(caddr_t data)
823 au_kcontext_t *kctx = GET_KCTX_PZ;
825 membar_consumer();
827 if (copyout((caddr_t)&(kctx->auk_statistics), data, sizeof (au_stat_t)))
828 return (EFAULT);
829 return (0);
832 static int
833 setstat(caddr_t data)
835 au_kcontext_t *kctx = GET_KCTX_PZ;
836 au_stat_t au_stat;
838 if (!(audit_policy & AUDIT_PERZONE) && !INGLOBALZONE(curproc))
839 return (EINVAL);
841 if (copyin(data, &au_stat, sizeof (au_stat_t)))
842 return (EFAULT);
844 if (au_stat.as_generated == CLEAR_VAL)
845 kctx->auk_statistics.as_generated = 0;
846 if (au_stat.as_nonattrib == CLEAR_VAL)
847 kctx->auk_statistics.as_nonattrib = 0;
848 if (au_stat.as_kernel == CLEAR_VAL)
849 kctx->auk_statistics.as_kernel = 0;
850 if (au_stat.as_audit == CLEAR_VAL)
851 kctx->auk_statistics.as_audit = 0;
852 if (au_stat.as_auditctl == CLEAR_VAL)
853 kctx->auk_statistics.as_auditctl = 0;
854 if (au_stat.as_enqueue == CLEAR_VAL)
855 kctx->auk_statistics.as_enqueue = 0;
856 if (au_stat.as_written == CLEAR_VAL)
857 kctx->auk_statistics.as_written = 0;
858 if (au_stat.as_wblocked == CLEAR_VAL)
859 kctx->auk_statistics.as_wblocked = 0;
860 if (au_stat.as_rblocked == CLEAR_VAL)
861 kctx->auk_statistics.as_rblocked = 0;
862 if (au_stat.as_dropped == CLEAR_VAL)
863 kctx->auk_statistics.as_dropped = 0;
864 if (au_stat.as_totalsize == CLEAR_VAL)
865 kctx->auk_statistics.as_totalsize = 0;
867 membar_producer();
869 return (0);
873 static int
874 setumask(caddr_t data)
876 STRUCT_DECL(auditinfo, user_info);
877 struct proc *p;
878 const auditinfo_addr_t *ainfo;
879 model_t model;
881 /* setumask not applicable in non-global zones without perzone policy */
882 if (!(audit_policy & AUDIT_PERZONE) && (!INGLOBALZONE(curproc)))
883 return (EINVAL);
885 model = get_udatamodel();
886 STRUCT_INIT(user_info, model);
888 if (copyin(data, STRUCT_BUF(user_info), STRUCT_SIZE(user_info)))
889 return (EFAULT);
891 mutex_enter(&pidlock); /* lock the process queue against updates */
892 for (p = practive; p != NULL; p = p->p_next) {
893 cred_t *cr;
895 /* if in non-global zone only modify processes in same zone */
896 if (!HASZONEACCESS(curproc, p->p_zone->zone_id))
897 continue;
899 mutex_enter(&p->p_lock); /* so process doesn't go away */
901 /* skip system processes and ones being created or going away */
902 if (p->p_stat == SIDL || p->p_stat == SZOMB ||
903 (p->p_flag & (SSYS | SEXITING | SEXITLWPS))) {
904 mutex_exit(&p->p_lock);
905 continue;
908 mutex_enter(&p->p_crlock);
909 crhold(cr = p->p_cred);
910 mutex_exit(&p->p_crlock);
911 ainfo = crgetauinfo(cr);
912 if (ainfo == NULL) {
913 mutex_exit(&p->p_lock);
914 crfree(cr);
915 continue;
918 if (ainfo->ai_auid == STRUCT_FGET(user_info, ai_auid)) {
919 au_mask_t mask;
920 int err;
923 * Here's a process which matches the specified auid.
924 * If its mask doesn't already match the new mask,
925 * save the new mask in the pad, to be picked up
926 * next syscall.
928 mask = STRUCT_FGET(user_info, ai_mask);
929 err = bcmp(&mask, &ainfo->ai_mask, sizeof (au_mask_t));
930 crfree(cr);
931 if (err != 0) {
932 struct p_audit_data *pad = P2A(p);
933 ASSERT(pad != NULL);
935 mutex_enter(&(pad->pad_lock));
936 pad->pad_flags |= PAD_SETMASK;
937 pad->pad_newmask = mask;
938 mutex_exit(&(pad->pad_lock));
941 * No need to call set_proc_pre_sys(), since
942 * t_pre_sys is ALWAYS on when audit is
943 * enabled...due to syscall auditing.
946 } else {
947 crfree(cr);
949 mutex_exit(&p->p_lock);
951 mutex_exit(&pidlock);
953 return (0);
956 static int
957 setsmask(caddr_t data)
959 STRUCT_DECL(auditinfo, user_info);
960 struct proc *p;
961 const auditinfo_addr_t *ainfo;
962 model_t model;
964 /* setsmask not applicable in non-global zones without perzone policy */
965 if (!(audit_policy & AUDIT_PERZONE) && (!INGLOBALZONE(curproc)))
966 return (EINVAL);
968 model = get_udatamodel();
969 STRUCT_INIT(user_info, model);
971 if (copyin(data, STRUCT_BUF(user_info), STRUCT_SIZE(user_info)))
972 return (EFAULT);
974 mutex_enter(&pidlock); /* lock the process queue against updates */
975 for (p = practive; p != NULL; p = p->p_next) {
976 cred_t *cr;
978 /* if in non-global zone only modify processes in same zone */
979 if (!HASZONEACCESS(curproc, p->p_zone->zone_id))
980 continue;
982 mutex_enter(&p->p_lock); /* so process doesn't go away */
984 /* skip system processes and ones being created or going away */
985 if (p->p_stat == SIDL || p->p_stat == SZOMB ||
986 (p->p_flag & (SSYS | SEXITING | SEXITLWPS))) {
987 mutex_exit(&p->p_lock);
988 continue;
991 mutex_enter(&p->p_crlock);
992 crhold(cr = p->p_cred);
993 mutex_exit(&p->p_crlock);
994 ainfo = crgetauinfo(cr);
995 if (ainfo == NULL) {
996 mutex_exit(&p->p_lock);
997 crfree(cr);
998 continue;
1001 if (ainfo->ai_asid == STRUCT_FGET(user_info, ai_asid)) {
1002 au_mask_t mask;
1003 int err;
1006 * Here's a process which matches the specified asid.
1007 * If its mask doesn't already match the new mask,
1008 * save the new mask in the pad, to be picked up
1009 * next syscall.
1011 mask = STRUCT_FGET(user_info, ai_mask);
1012 err = bcmp(&mask, &ainfo->ai_mask, sizeof (au_mask_t));
1013 crfree(cr);
1014 if (err != 0) {
1015 struct p_audit_data *pad = P2A(p);
1016 ASSERT(pad != NULL);
1018 mutex_enter(&(pad->pad_lock));
1019 pad->pad_flags |= PAD_SETMASK;
1020 pad->pad_newmask = mask;
1021 mutex_exit(&(pad->pad_lock));
1024 * No need to call set_proc_pre_sys(), since
1025 * t_pre_sys is ALWAYS on when audit is
1026 * enabled...due to syscall auditing.
1029 } else {
1030 crfree(cr);
1032 mutex_exit(&p->p_lock);
1034 mutex_exit(&pidlock);
1036 return (0);
1040 * Get the current audit state of the system
1042 static int
1043 getcond(caddr_t data)
1045 au_kcontext_t *kctx = GET_KCTX_PZ;
1047 if (copyout(&(kctx->auk_auditstate), data, sizeof (int)))
1048 return (EFAULT);
1050 return (0);
1054 * Set the current audit state of the system to on (AUC_AUDITING) or
1055 * off (AUC_NOAUDIT).
1057 /* ARGSUSED */
1058 static int
1059 setcond(caddr_t data)
1061 int auditstate;
1062 au_kcontext_t *kctx;
1064 if (!(audit_policy & AUDIT_PERZONE) && (!INGLOBALZONE(curproc)))
1065 return (EINVAL);
1067 kctx = GET_KCTX_NGZ;
1069 if (copyin(data, &auditstate, sizeof (int)))
1070 return (EFAULT);
1072 switch (auditstate) {
1073 case AUC_AUDITING: /* Turn auditing on */
1074 if (audit_active == C2AUDIT_UNLOADED)
1075 audit_init_module();
1076 kctx->auk_auditstate = AUC_AUDITING;
1077 if (!(audit_policy & AUDIT_PERZONE) && INGLOBALZONE(curproc))
1078 set_all_zone_usr_proc_sys(ALL_ZONES);
1079 else
1080 set_all_zone_usr_proc_sys(curproc->p_zone->zone_id);
1081 break;
1083 case AUC_NOAUDIT: /* Turn auditing off */
1084 if (kctx->auk_auditstate == AUC_NOAUDIT)
1085 break;
1086 kctx->auk_auditstate = AUC_NOAUDIT;
1088 /* clear out the audit queue */
1090 mutex_enter(&(kctx->auk_queue.lock));
1091 if (kctx->auk_queue.wt_block)
1092 cv_broadcast(&(kctx->auk_queue.write_cv));
1094 /* unblock au_output_thread */
1095 cv_broadcast(&(kctx->auk_queue.read_cv));
1097 mutex_exit(&(kctx->auk_queue.lock));
1098 break;
1100 default:
1101 return (EINVAL);
1104 return (0);
1107 static int
1108 getclass(caddr_t data)
1110 au_evclass_map_t event;
1111 au_kcontext_t *kctx = GET_KCTX_PZ;
1113 if (copyin(data, &event, sizeof (au_evclass_map_t)))
1114 return (EFAULT);
1116 if (event.ec_number > MAX_KEVENTS)
1117 return (EINVAL);
1119 event.ec_class = kctx->auk_ets[event.ec_number];
1121 if (copyout(&event, data, sizeof (au_evclass_map_t)))
1122 return (EFAULT);
1124 return (0);
1127 static int
1128 setclass(caddr_t data)
1130 au_evclass_map_t event;
1131 au_kcontext_t *kctx;
1133 if (!(audit_policy & AUDIT_PERZONE) && !INGLOBALZONE(curproc))
1134 return (EINVAL);
1136 kctx = GET_KCTX_NGZ;
1138 if (copyin(data, &event, sizeof (au_evclass_map_t)))
1139 return (EFAULT);
1141 if (event.ec_number > MAX_KEVENTS)
1142 return (EINVAL);
1144 kctx->auk_ets[event.ec_number] = event.ec_class;
1146 return (0);
1149 static int
1150 getpinfo(caddr_t data)
1152 STRUCT_DECL(auditpinfo, apinfo);
1153 proc_t *proc;
1154 const auditinfo_addr_t *ainfo;
1155 model_t model;
1156 cred_t *cr, *newcred;
1158 model = get_udatamodel();
1159 STRUCT_INIT(apinfo, model);
1161 if (copyin(data, STRUCT_BUF(apinfo), STRUCT_SIZE(apinfo)))
1162 return (EFAULT);
1164 newcred = cralloc();
1166 mutex_enter(&pidlock);
1167 if ((proc = prfind(STRUCT_FGET(apinfo, ap_pid))) == NULL) {
1168 mutex_exit(&pidlock);
1169 crfree(newcred);
1170 return (ESRCH); /* no such process */
1172 mutex_enter(&proc->p_lock); /* so process doesn't go away */
1173 mutex_exit(&pidlock);
1175 audit_update_context(proc, newcred); /* make sure it's up-to-date */
1177 mutex_enter(&proc->p_crlock);
1178 crhold(cr = proc->p_cred);
1179 mutex_exit(&proc->p_crlock);
1180 mutex_exit(&proc->p_lock);
1182 ainfo = crgetauinfo(cr);
1183 if (ainfo == NULL) {
1184 crfree(cr);
1185 return (EINVAL);
1188 /* designated process has an ipv6 address? */
1189 if (ainfo->ai_termid.at_type == AU_IPv6) {
1190 crfree(cr);
1191 return (EOVERFLOW);
1194 STRUCT_FSET(apinfo, ap_auid, ainfo->ai_auid);
1195 STRUCT_FSET(apinfo, ap_asid, ainfo->ai_asid);
1196 #ifdef _LP64
1197 if (model == DATAMODEL_ILP32) {
1198 dev32_t dev;
1199 /* convert internal 64 bit form to 32 bit version */
1200 if (cmpldev(&dev, ainfo->ai_termid.at_port) == 0) {
1201 crfree(cr);
1202 return (EOVERFLOW);
1204 STRUCT_FSET(apinfo, ap_termid.port, dev);
1205 } else
1206 STRUCT_FSET(apinfo, ap_termid.port, ainfo->ai_termid.at_port);
1207 #else
1208 STRUCT_FSET(apinfo, ap_termid.port, ainfo->ai_termid.at_port);
1209 #endif
1210 STRUCT_FSET(apinfo, ap_termid.machine, ainfo->ai_termid.at_addr[0]);
1211 STRUCT_FSET(apinfo, ap_mask, ainfo->ai_mask);
1213 crfree(cr);
1215 if (copyout(STRUCT_BUF(apinfo), data, STRUCT_SIZE(apinfo)))
1216 return (EFAULT);
1218 return (0);
1221 static int
1222 getpinfo_addr(caddr_t data, int len)
1224 STRUCT_DECL(auditpinfo_addr, apinfo);
1225 proc_t *proc;
1226 const auditinfo_addr_t *ainfo;
1227 model_t model;
1228 cred_t *cr, *newcred;
1230 model = get_udatamodel();
1231 STRUCT_INIT(apinfo, model);
1233 if (len < STRUCT_SIZE(apinfo))
1234 return (EOVERFLOW);
1236 if (copyin(data, STRUCT_BUF(apinfo), STRUCT_SIZE(apinfo)))
1237 return (EFAULT);
1239 newcred = cralloc();
1241 mutex_enter(&pidlock);
1242 if ((proc = prfind(STRUCT_FGET(apinfo, ap_pid))) == NULL) {
1243 mutex_exit(&pidlock);
1244 crfree(newcred);
1245 return (ESRCH);
1247 mutex_enter(&proc->p_lock); /* so process doesn't go away */
1248 mutex_exit(&pidlock);
1250 audit_update_context(proc, newcred); /* make sure it's up-to-date */
1252 mutex_enter(&proc->p_crlock);
1253 crhold(cr = proc->p_cred);
1254 mutex_exit(&proc->p_crlock);
1255 mutex_exit(&proc->p_lock);
1257 ainfo = crgetauinfo(cr);
1258 if (ainfo == NULL) {
1259 crfree(cr);
1260 return (EINVAL);
1263 STRUCT_FSET(apinfo, ap_auid, ainfo->ai_auid);
1264 STRUCT_FSET(apinfo, ap_asid, ainfo->ai_asid);
1265 #ifdef _LP64
1266 if (model == DATAMODEL_ILP32) {
1267 dev32_t dev;
1268 /* convert internal 64 bit form to 32 bit version */
1269 if (cmpldev(&dev, ainfo->ai_termid.at_port) == 0) {
1270 crfree(cr);
1271 return (EOVERFLOW);
1273 STRUCT_FSET(apinfo, ap_termid.at_port, dev);
1274 } else
1275 STRUCT_FSET(apinfo, ap_termid.at_port,
1276 ainfo->ai_termid.at_port);
1277 #else
1278 STRUCT_FSET(apinfo, ap_termid.at_port, ainfo->ai_termid.at_port);
1279 #endif
1280 STRUCT_FSET(apinfo, ap_termid.at_type, ainfo->ai_termid.at_type);
1281 STRUCT_FSET(apinfo, ap_termid.at_addr[0], ainfo->ai_termid.at_addr[0]);
1282 STRUCT_FSET(apinfo, ap_termid.at_addr[1], ainfo->ai_termid.at_addr[1]);
1283 STRUCT_FSET(apinfo, ap_termid.at_addr[2], ainfo->ai_termid.at_addr[2]);
1284 STRUCT_FSET(apinfo, ap_termid.at_addr[3], ainfo->ai_termid.at_addr[3]);
1285 STRUCT_FSET(apinfo, ap_mask, ainfo->ai_mask);
1287 crfree(cr);
1289 if (copyout(STRUCT_BUF(apinfo), data, STRUCT_SIZE(apinfo)))
1290 return (EFAULT);
1292 return (0);
1295 static int
1296 setpmask(caddr_t data)
1298 STRUCT_DECL(auditpinfo, apinfo);
1299 proc_t *proc;
1300 cred_t *newcred;
1301 auditinfo_addr_t *ainfo;
1302 struct p_audit_data *pad;
1304 model_t model;
1306 model = get_udatamodel();
1307 STRUCT_INIT(apinfo, model);
1309 if (copyin(data, STRUCT_BUF(apinfo), STRUCT_SIZE(apinfo)))
1310 return (EFAULT);
1312 mutex_enter(&pidlock);
1313 if ((proc = prfind(STRUCT_FGET(apinfo, ap_pid))) == NULL) {
1314 mutex_exit(&pidlock);
1315 return (ESRCH);
1317 mutex_enter(&proc->p_lock); /* so process doesn't go away */
1318 mutex_exit(&pidlock);
1320 newcred = cralloc();
1321 if ((ainfo = crgetauinfo_modifiable(newcred)) == NULL) {
1322 mutex_exit(&proc->p_lock);
1323 crfree(newcred);
1324 return (EINVAL);
1327 mutex_enter(&proc->p_crlock);
1328 crcopy_to(proc->p_cred, newcred);
1329 proc->p_cred = newcred;
1331 ainfo->ai_mask = STRUCT_FGET(apinfo, ap_mask);
1334 * Unlock. No need to broadcast changes via set_proc_pre_sys(),
1335 * since t_pre_sys is ALWAYS on when audit is enabled... due to
1336 * syscall auditing.
1338 crfree(newcred);
1339 mutex_exit(&proc->p_crlock);
1341 /* Reset flag for any previous pending mask change; this supercedes */
1342 pad = P2A(proc);
1343 ASSERT(pad != NULL);
1344 mutex_enter(&(pad->pad_lock));
1345 pad->pad_flags &= ~PAD_SETMASK;
1346 mutex_exit(&(pad->pad_lock));
1348 mutex_exit(&proc->p_lock);
1350 return (0);
1354 * The out of control system call
1355 * This is audit kitchen sink aka auditadm, aka auditon
1358 auditctl(
1359 int cmd,
1360 caddr_t data,
1361 int length)
1363 int result;
1365 switch (cmd) {
1366 case A_GETAMASK:
1367 case A_GETCOND:
1368 case A_GETCAR:
1369 case A_GETCLASS:
1370 case A_GETCWD:
1371 case A_GETKAUDIT:
1372 case A_GETKMASK:
1373 case A_GETPINFO:
1374 case A_GETPINFO_ADDR:
1375 case A_GETPOLICY:
1376 case A_GETQCTRL:
1377 case A_GETSTAT:
1378 if (secpolicy_audit_getattr(CRED(), B_FALSE) != 0)
1379 return (EPERM);
1380 break;
1381 default:
1382 if (secpolicy_audit_config(CRED()) != 0)
1383 return (EPERM);
1384 break;
1387 switch (cmd) {
1388 case A_GETPOLICY:
1389 result = getpolicy(data);
1390 break;
1391 case A_SETPOLICY:
1392 result = setpolicy(data);
1393 break;
1394 case A_GETAMASK:
1395 result = getamask(data);
1396 break;
1397 case A_SETAMASK:
1398 result = setamask(data);
1399 break;
1400 case A_GETKMASK:
1401 result = getkmask(data);
1402 break;
1403 case A_SETKMASK:
1404 result = setkmask(data);
1405 break;
1406 case A_GETKAUDIT:
1407 result = getkaudit(data, length);
1408 break;
1409 case A_SETKAUDIT:
1410 result = setkaudit(data, length);
1411 break;
1412 case A_GETQCTRL:
1413 result = getqctrl(data);
1414 break;
1415 case A_SETQCTRL:
1416 result = setqctrl(data);
1417 break;
1418 case A_GETCWD:
1419 result = getcwd(data, length);
1420 break;
1421 case A_GETCAR:
1422 result = getcar(data, length);
1423 break;
1424 case A_GETSTAT:
1425 result = getstat(data);
1426 break;
1427 case A_SETSTAT:
1428 result = setstat(data);
1429 break;
1430 case A_SETUMASK:
1431 result = setumask(data);
1432 break;
1433 case A_SETSMASK:
1434 result = setsmask(data);
1435 break;
1436 case A_GETCOND:
1437 result = getcond(data);
1438 break;
1439 case A_SETCOND:
1440 result = setcond(data);
1441 break;
1442 case A_GETCLASS:
1443 result = getclass(data);
1444 break;
1445 case A_SETCLASS:
1446 result = setclass(data);
1447 break;
1448 case A_GETPINFO:
1449 result = getpinfo(data);
1450 break;
1451 case A_GETPINFO_ADDR:
1452 result = getpinfo_addr(data, length);
1453 break;
1454 case A_SETPMASK:
1455 result = setpmask(data);
1456 break;
1457 default:
1458 result = EINVAL;
1459 break;
1461 return (result);