1/*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright (c) 2013, Ira Cooper.  All rights reserved.
23 * Copyright 2020 Nexenta by DDN, Inc. All rights reserved.
24 */
25/*
26 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
27 */
28
29/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
30/*	  All Rights Reserved	*/
31
32/*
33 * University Copyright- Copyright (c) 1982, 1986, 1988
34 * The Regents of the University of California
35 * All Rights Reserved
36 *
37 * University Acknowledgment- Portions of this document are derived from
38 * software developed by the University of California, Berkeley, and its
39 * contributors.
40 */
41
42#include <sys/types.h>
43#include <sys/sysmacros.h>
44#include <sys/param.h>
45#include <sys/systm.h>
46#include <sys/cred_impl.h>
47#include <sys/policy.h>
48#include <sys/vnode.h>
49#include <sys/errno.h>
50#include <sys/kmem.h>
51#include <sys/user.h>
52#include <sys/proc.h>
53#include <sys/syscall.h>
54#include <sys/debug.h>
55#include <sys/atomic.h>
56#include <sys/ucred.h>
57#include <sys/prsystm.h>
58#include <sys/modctl.h>
59#include <sys/avl.h>
60#include <sys/door.h>
61#include <c2/audit.h>
62#include <sys/zone.h>
63#include <sys/tsol/label.h>
64#include <sys/sid.h>
65#include <sys/idmap.h>
66#include <sys/klpd.h>
67#include <sys/varargs.h>
68#include <sys/sysconf.h>
69#include <util/qsort.h>
70
71
72/* Ephemeral IDs Zones specific data */
73typedef struct ephemeral_zsd {
74	uid_t		min_uid;
75	uid_t		last_uid;
76	gid_t		min_gid;
77	gid_t		last_gid;
78	kmutex_t	eph_lock;
79	cred_t		*eph_nobody;
80} ephemeral_zsd_t;
81
82static void crgrphold(credgrp_t *);
83
84#define	CREDGRPSZ(ngrp)	(sizeof (credgrp_t) + ((ngrp - 1) * sizeof (gid_t)))
85
86static kmutex_t		ephemeral_zone_mutex;
87static zone_key_t	ephemeral_zone_key;
88
89static struct kmem_cache *cred_cache;
90static size_t		crsize = 0;
91static int		audoff = 0;
92uint32_t		ucredsize;
93cred_t			*kcred;
94static cred_t		*dummycr;
95
96int rstlink;		/* link(2) restricted to files owned by user? */
97
98static int get_c2audit_load(void);
99
100#define	CR_AUINFO(c)	(auditinfo_addr_t *)((audoff == 0) ? NULL : \
101			    ((char *)(c)) + audoff)
102
103#define	REMOTE_PEER_CRED(c)	((c)->cr_gid == -1)
104
105#define	BIN_GROUP_SEARCH_CUTOFF	16
106
107static boolean_t hasephids = B_FALSE;
108
109static ephemeral_zsd_t *
110get_ephemeral_zsd(zone_t *zone)
111{
112	ephemeral_zsd_t *eph_zsd;
113
114	eph_zsd = zone_getspecific(ephemeral_zone_key, zone);
115	if (eph_zsd != NULL) {
116		return (eph_zsd);
117	}
118
119	mutex_enter(&ephemeral_zone_mutex);
120	eph_zsd = zone_getspecific(ephemeral_zone_key, zone);
121	if (eph_zsd == NULL) {
122		eph_zsd = kmem_zalloc(sizeof (ephemeral_zsd_t), KM_SLEEP);
123		eph_zsd->min_uid = MAXUID;
124		eph_zsd->last_uid = IDMAP_WK__MAX_UID;
125		eph_zsd->min_gid = MAXUID;
126		eph_zsd->last_gid = IDMAP_WK__MAX_GID;
127		mutex_init(&eph_zsd->eph_lock, NULL, MUTEX_DEFAULT, NULL);
128
129		/*
130		 * nobody is used to map SID containing CRs.
131		 */
132		eph_zsd->eph_nobody = crdup(zone->zone_kcred);
133		(void) crsetugid(eph_zsd->eph_nobody, UID_NOBODY, GID_NOBODY);
134		CR_FLAGS(eph_zsd->eph_nobody) = 0;
135		eph_zsd->eph_nobody->cr_zone = zone;
136
137		(void) zone_setspecific(ephemeral_zone_key, zone, eph_zsd);
138	}
139	mutex_exit(&ephemeral_zone_mutex);
140	return (eph_zsd);
141}
142
143static cred_t *crdup_flags(const cred_t *, int);
144static cred_t *cralloc_flags(int);
145
146/*
147 * This function is called when a zone is destroyed
148 */
149static void
150/* ARGSUSED */
151destroy_ephemeral_zsd(zoneid_t zone_id, void *arg)
152{
153	ephemeral_zsd_t *eph_zsd = arg;
154	if (eph_zsd != NULL) {
155		mutex_destroy(&eph_zsd->eph_lock);
156		crfree(eph_zsd->eph_nobody);
157		kmem_free(eph_zsd, sizeof (ephemeral_zsd_t));
158	}
159}
160
161
162
163/*
164 * Initialize credentials data structures.
165 */
166
167void
168cred_init(void)
169{
170	priv_init();
171
172	crsize = sizeof (cred_t);
173
174	if (get_c2audit_load() > 0) {
175#ifdef _LP64
176		/* assure audit context is 64-bit aligned */
177		audoff = (crsize +
178		    sizeof (int64_t) - 1) & ~(sizeof (int64_t) - 1);
179#else	/* _LP64 */
180		audoff = crsize;
181#endif	/* _LP64 */
182		crsize = audoff + sizeof (auditinfo_addr_t);
183		crsize = (crsize + sizeof (int) - 1) & ~(sizeof (int) - 1);
184	}
185
186	cred_cache = kmem_cache_create("cred_cache", crsize, 0,
187	    NULL, NULL, NULL, NULL, NULL, 0);
188
189	/*
190	 * dummycr is used to copy initial state for creds.
191	 */
192	dummycr = cralloc();
193	bzero(dummycr, crsize);
194	dummycr->cr_ref = 1;
195	dummycr->cr_uid = (uid_t)-1;
196	dummycr->cr_gid = (gid_t)-1;
197	dummycr->cr_ruid = (uid_t)-1;
198	dummycr->cr_rgid = (gid_t)-1;
199	dummycr->cr_suid = (uid_t)-1;
200	dummycr->cr_sgid = (gid_t)-1;
201
202
203	/*
204	 * kcred is used by anything that needs all privileges; it's
205	 * also the template used for crget as it has all the compatible
206	 * sets filled in.
207	 */
208	kcred = cralloc();
209
210	bzero(kcred, crsize);
211	kcred->cr_ref = 1;
212
213	/* kcred is never freed, so we don't need zone_cred_hold here */
214	kcred->cr_zone = &zone0;
215
216	priv_fillset(&CR_LPRIV(kcred));
217	CR_IPRIV(kcred) = *priv_basic;
218
219	priv_addset(&CR_IPRIV(kcred), PRIV_PROC_SECFLAGS);
220
221	/* Not a basic privilege, if chown is not restricted add it to I0 */
222	if (!rstchown)
223		priv_addset(&CR_IPRIV(kcred), PRIV_FILE_CHOWN_SELF);
224
225	/* Basic privilege, if link is restricted remove it from I0 */
226	if (rstlink)
227		priv_delset(&CR_IPRIV(kcred), PRIV_FILE_LINK_ANY);
228
229	CR_EPRIV(kcred) = CR_PPRIV(kcred) = CR_IPRIV(kcred);
230
231	CR_FLAGS(kcred) = NET_MAC_AWARE;
232
233	/*
234	 * Set up credentials of p0.
235	 */
236	ttoproc(curthread)->p_cred = kcred;
237	curthread->t_cred = kcred;
238
239	ucredsize = UCRED_SIZE;
240
241	mutex_init(&ephemeral_zone_mutex, NULL, MUTEX_DEFAULT, NULL);
242	zone_key_create(&ephemeral_zone_key, NULL, NULL, destroy_ephemeral_zsd);
243}
244
245/*
246 * Allocate (nearly) uninitialized cred_t.
247 */
248static cred_t *
249cralloc_flags(int flgs)
250{
251	cred_t *cr = kmem_cache_alloc(cred_cache, flgs);
252
253	if (cr == NULL)
254		return (NULL);
255
256	cr->cr_ref = 1;		/* So we can crfree() */
257	cr->cr_zone = NULL;
258	cr->cr_label = NULL;
259	cr->cr_ksid = NULL;
260	cr->cr_klpd = NULL;
261	cr->cr_grps = NULL;
262	return (cr);
263}
264
265cred_t *
266cralloc(void)
267{
268	return (cralloc_flags(KM_SLEEP));
269}
270
271/*
272 * As cralloc but prepared for ksid change (if appropriate).
273 */
274cred_t *
275cralloc_ksid(void)
276{
277	cred_t *cr = cralloc();
278	if (hasephids)
279		cr->cr_ksid = kcrsid_alloc();
280	return (cr);
281}
282
283/*
284 * Allocate a initialized cred structure and crhold() it.
285 * Initialized means: all ids 0, group count 0, L=Full, E=P=I=I0
286 */
287cred_t *
288crget(void)
289{
290	cred_t *cr = kmem_cache_alloc(cred_cache, KM_SLEEP);
291
292	bcopy(zone_kcred(), cr, crsize);
293	cr->cr_ref = 1;
294	zone_cred_hold(cr->cr_zone);
295	if (cr->cr_label)
296		label_hold(cr->cr_label);
297	ASSERT(cr->cr_klpd == NULL);
298	ASSERT(cr->cr_grps == NULL);
299	return (cr);
300}
301
302/*
303 * Broadcast the cred to all the threads in the process.
304 * The current thread's credentials can be set right away, but other
305 * threads must wait until the start of the next system call or trap.
306 * This avoids changing the cred in the middle of a system call.
307 *
308 * The cred has already been held for the process and the thread (2 holds),
309 * and p->p_cred set.
310 *
311 * p->p_crlock shouldn't be held here, since p_lock must be acquired.
312 */
313void
314crset(proc_t *p, cred_t *cr)
315{
316	kthread_id_t	t;
317	kthread_id_t	first;
318	cred_t *oldcr;
319
320	ASSERT(p == curproc);	/* assumes p_lwpcnt can't change */
321
322	/*
323	 * DTrace accesses t_cred in probe context.  t_cred must always be
324	 * either NULL, or point to a valid, allocated cred structure.
325	 */
326	t = curthread;
327	oldcr = t->t_cred;
328	t->t_cred = cr;		/* the cred is held by caller for this thread */
329	crfree(oldcr);		/* free the old cred for the thread */
330
331	/*
332	 * Broadcast to other threads, if any.
333	 */
334	if (p->p_lwpcnt > 1) {
335		mutex_enter(&p->p_lock);	/* to keep thread list safe */
336		first = curthread;
337		for (t = first->t_forw; t != first; t = t->t_forw)
338			t->t_pre_sys = 1; /* so syscall will get new cred */
339		mutex_exit(&p->p_lock);
340	}
341}
342
343/*
344 * Put a hold on a cred structure.
345 */
346void
347crhold(cred_t *cr)
348{
349	ASSERT(cr->cr_ref != 0xdeadbeef && cr->cr_ref != 0);
350	atomic_inc_32(&cr->cr_ref);
351}
352
353/*
354 * Release previous hold on a cred structure.  Free it if refcnt == 0.
355 * If cred uses label different from zone label, free it.
356 */
357void
358crfree(cred_t *cr)
359{
360	ASSERT(cr->cr_ref != 0xdeadbeef && cr->cr_ref != 0);
361	if (atomic_dec_32_nv(&cr->cr_ref) == 0) {
362		ASSERT(cr != kcred);
363		if (cr->cr_label)
364			label_rele(cr->cr_label);
365		if (cr->cr_klpd)
366			crklpd_rele(cr->cr_klpd);
367		if (cr->cr_zone)
368			zone_cred_rele(cr->cr_zone);
369		if (cr->cr_ksid)
370			kcrsid_rele(cr->cr_ksid);
371		if (cr->cr_grps)
372			crgrprele(cr->cr_grps);
373
374		kmem_cache_free(cred_cache, cr);
375	}
376}
377
378/*
379 * Copy a cred structure to a new one and free the old one.
380 *	The new cred will have two references.  One for the calling process,
381 *	and one for the thread.
382 */
383cred_t *
384crcopy(cred_t *cr)
385{
386	cred_t *newcr;
387
388	newcr = cralloc();
389	bcopy(cr, newcr, crsize);
390	if (newcr->cr_zone)
391		zone_cred_hold(newcr->cr_zone);
392	if (newcr->cr_label)
393		label_hold(newcr->cr_label);
394	if (newcr->cr_ksid)
395		kcrsid_hold(newcr->cr_ksid);
396	if (newcr->cr_klpd)
397		crklpd_hold(newcr->cr_klpd);
398	if (newcr->cr_grps)
399		crgrphold(newcr->cr_grps);
400	crfree(cr);
401	newcr->cr_ref = 2;		/* caller gets two references */
402	return (newcr);
403}
404
405/*
406 * Copy a cred structure to a new one and free the old one.
407 *	The new cred will have two references.  One for the calling process,
408 *	and one for the thread.
409 * This variation on crcopy uses a pre-allocated structure for the
410 * "new" cred.
411 */
412void
413crcopy_to(cred_t *oldcr, cred_t *newcr)
414{
415	credsid_t *nkcr = newcr->cr_ksid;
416
417	bcopy(oldcr, newcr, crsize);
418	if (newcr->cr_zone)
419		zone_cred_hold(newcr->cr_zone);
420	if (newcr->cr_label)
421		label_hold(newcr->cr_label);
422	if (newcr->cr_klpd)
423		crklpd_hold(newcr->cr_klpd);
424	if (newcr->cr_grps)
425		crgrphold(newcr->cr_grps);
426	if (nkcr) {
427		newcr->cr_ksid = nkcr;
428		kcrsidcopy_to(oldcr->cr_ksid, newcr->cr_ksid);
429	} else if (newcr->cr_ksid)
430		kcrsid_hold(newcr->cr_ksid);
431	crfree(oldcr);
432	newcr->cr_ref = 2;		/* caller gets two references */
433}
434
435/*
436 * Dup a cred struct to a new held one.
437 *	The old cred is not freed.
438 */
439static cred_t *
440crdup_flags(const cred_t *cr, int flgs)
441{
442	cred_t *newcr;
443
444	newcr = cralloc_flags(flgs);
445
446	if (newcr == NULL)
447		return (NULL);
448
449	bcopy(cr, newcr, crsize);
450	if (newcr->cr_zone)
451		zone_cred_hold(newcr->cr_zone);
452	if (newcr->cr_label)
453		label_hold(newcr->cr_label);
454	if (newcr->cr_klpd)
455		crklpd_hold(newcr->cr_klpd);
456	if (newcr->cr_ksid)
457		kcrsid_hold(newcr->cr_ksid);
458	if (newcr->cr_grps)
459		crgrphold(newcr->cr_grps);
460	newcr->cr_ref = 1;
461	return (newcr);
462}
463
464cred_t *
465crdup(cred_t *cr)
466{
467	return (crdup_flags(cr, KM_SLEEP));
468}
469
470/*
471 * Dup a cred struct to a new held one.
472 *	The old cred is not freed.
473 * This variation on crdup uses a pre-allocated structure for the
474 * "new" cred.
475 */
476void
477crdup_to(cred_t *oldcr, cred_t *newcr)
478{
479	credsid_t *nkcr = newcr->cr_ksid;
480
481	bcopy(oldcr, newcr, crsize);
482	if (newcr->cr_zone)
483		zone_cred_hold(newcr->cr_zone);
484	if (newcr->cr_label)
485		label_hold(newcr->cr_label);
486	if (newcr->cr_klpd)
487		crklpd_hold(newcr->cr_klpd);
488	if (newcr->cr_grps)
489		crgrphold(newcr->cr_grps);
490	if (nkcr) {
491		newcr->cr_ksid = nkcr;
492		kcrsidcopy_to(oldcr->cr_ksid, newcr->cr_ksid);
493	} else if (newcr->cr_ksid)
494		kcrsid_hold(newcr->cr_ksid);
495	newcr->cr_ref = 1;
496}
497
498/*
499 * Return the (held) credentials for the current running process.
500 */
501cred_t *
502crgetcred(void)
503{
504	cred_t *cr;
505	proc_t *p;
506
507	p = ttoproc(curthread);
508	mutex_enter(&p->p_crlock);
509	crhold(cr = p->p_cred);
510	mutex_exit(&p->p_crlock);
511	return (cr);
512}
513
514/*
515 * Backward compatibility check for suser().
516 * Accounting flag is now set in the policy functions; auditing is
517 * done through use of privilege in the audit trail.
518 */
519int
520suser(cred_t *cr)
521{
522	return (PRIV_POLICY(cr, PRIV_SYS_SUSER_COMPAT, B_FALSE, EPERM, NULL)
523	    == 0);
524}
525
526/*
527 * Determine whether the supplied group id is a member of the group
528 * described by the supplied credentials.
529 */
530int
531groupmember(gid_t gid, const cred_t *cr)
532{
533	if (gid == cr->cr_gid)
534		return (1);
535	return (supgroupmember(gid, cr));
536}
537
538/*
539 * As groupmember but only check against the supplemental groups.
540 */
541int
542supgroupmember(gid_t gid, const cred_t *cr)
543{
544	int hi, lo;
545	credgrp_t *grps = cr->cr_grps;
546	const gid_t *gp, *endgp;
547
548	if (grps == NULL)
549		return (0);
550
551	/* For a small number of groups, use sequentials search. */
552	if (grps->crg_ngroups <= BIN_GROUP_SEARCH_CUTOFF) {
553		endgp = &grps->crg_groups[grps->crg_ngroups];
554		for (gp = grps->crg_groups; gp < endgp; gp++)
555			if (*gp == gid)
556				return (1);
557		return (0);
558	}
559
560	/* We use binary search when we have many groups. */
561	lo = 0;
562	hi = grps->crg_ngroups - 1;
563	gp = grps->crg_groups;
564
565	do {
566		int m = (lo + hi) / 2;
567
568		if (gid > gp[m])
569			lo = m + 1;
570		else if (gid < gp[m])
571			hi = m - 1;
572		else
573			return (1);
574	} while (lo <= hi);
575
576	return (0);
577}
578
579/*
580 * This function is called to check whether the credentials set
581 * "scrp" has permission to act on credentials set "tcrp".  It enforces the
582 * permission requirements needed to send a signal to a process.
583 * The same requirements are imposed by other system calls, however.
584 *
585 * The rules are:
586 * (1) if the credentials are the same, the check succeeds
587 * (2) if the zone ids don't match, and scrp is not in the global zone or
588 *     does not have the PRIV_PROC_ZONE privilege, the check fails
589 * (3) if the real or effective user id of scrp matches the real or saved
590 *     user id of tcrp or scrp has the PRIV_PROC_OWNER privilege, the check
591 *     succeeds
592 * (4) otherwise, the check fails
593 */
594int
595hasprocperm(const cred_t *tcrp, const cred_t *scrp)
596{
597	if (scrp == tcrp)
598		return (1);
599	if (scrp->cr_zone != tcrp->cr_zone &&
600	    (scrp->cr_zone != global_zone ||
601	    secpolicy_proc_zone(scrp) != 0))
602		return (0);
603	if (scrp->cr_uid == tcrp->cr_ruid ||
604	    scrp->cr_ruid == tcrp->cr_ruid ||
605	    scrp->cr_uid  == tcrp->cr_suid ||
606	    scrp->cr_ruid == tcrp->cr_suid ||
607	    !PRIV_POLICY(scrp, PRIV_PROC_OWNER, B_FALSE, EPERM, "hasprocperm"))
608		return (1);
609	return (0);
610}
611
612/*
613 * This interface replaces hasprocperm; it works like hasprocperm but
614 * additionally returns success if the proc_t's match
615 * It is the preferred interface for most uses.
616 * And it will acquire p_crlock itself, so it assert's that it shouldn't
617 * be held.
618 */
619int
620prochasprocperm(proc_t *tp, proc_t *sp, const cred_t *scrp)
621{
622	int rets;
623	cred_t *tcrp;
624
625	ASSERT(MUTEX_NOT_HELD(&tp->p_crlock));
626
627	if (tp == sp)
628		return (1);
629
630	if (tp->p_sessp != sp->p_sessp && secpolicy_basic_proc(scrp) != 0)
631		return (0);
632
633	mutex_enter(&tp->p_crlock);
634	crhold(tcrp = tp->p_cred);
635	mutex_exit(&tp->p_crlock);
636	rets = hasprocperm(tcrp, scrp);
637	crfree(tcrp);
638
639	return (rets);
640}
641
642/*
643 * This routine is used to compare two credentials to determine if
644 * they refer to the same "user".  If the pointers are equal, then
645 * they must refer to the same user.  Otherwise, the contents of
646 * the credentials are compared to see whether they are equivalent.
647 *
648 * This routine returns 0 if the credentials refer to the same user,
649 * 1 if they do not.
650 */
651int
652crcmp(const cred_t *cr1, const cred_t *cr2)
653{
654	credgrp_t *grp1, *grp2;
655
656	if (cr1 == cr2)
657		return (0);
658
659	if (cr1->cr_uid == cr2->cr_uid &&
660	    cr1->cr_gid == cr2->cr_gid &&
661	    cr1->cr_ruid == cr2->cr_ruid &&
662	    cr1->cr_rgid == cr2->cr_rgid &&
663	    cr1->cr_zone == cr2->cr_zone &&
664	    ((grp1 = cr1->cr_grps) == (grp2 = cr2->cr_grps) ||
665	    (grp1 != NULL && grp2 != NULL &&
666	    grp1->crg_ngroups == grp2->crg_ngroups &&
667	    bcmp(grp1->crg_groups, grp2->crg_groups,
668	    grp1->crg_ngroups * sizeof (gid_t)) == 0))) {
669		return (!priv_isequalset(&CR_OEPRIV(cr1), &CR_OEPRIV(cr2)));
670	}
671	return (1);
672}
673
674/*
675 * Read access functions to cred_t.
676 */
677uid_t
678crgetuid(const cred_t *cr)
679{
680	return (cr->cr_uid);
681}
682
683uid_t
684crgetruid(const cred_t *cr)
685{
686	return (cr->cr_ruid);
687}
688
689uid_t
690crgetsuid(const cred_t *cr)
691{
692	return (cr->cr_suid);
693}
694
695gid_t
696crgetgid(const cred_t *cr)
697{
698	return (cr->cr_gid);
699}
700
701gid_t
702crgetrgid(const cred_t *cr)
703{
704	return (cr->cr_rgid);
705}
706
707gid_t
708crgetsgid(const cred_t *cr)
709{
710	return (cr->cr_sgid);
711}
712
713const auditinfo_addr_t *
714crgetauinfo(const cred_t *cr)
715{
716	return ((const auditinfo_addr_t *)CR_AUINFO(cr));
717}
718
719auditinfo_addr_t *
720crgetauinfo_modifiable(cred_t *cr)
721{
722	return (CR_AUINFO(cr));
723}
724
725zoneid_t
726crgetzoneid(const cred_t *cr)
727{
728	return (cr->cr_zone == NULL ?
729	    (cr->cr_uid == -1 ? (zoneid_t)-1 : GLOBAL_ZONEID) :
730	    cr->cr_zone->zone_id);
731}
732
733projid_t
734crgetprojid(const cred_t *cr)
735{
736	return (cr->cr_projid);
737}
738
739zone_t *
740crgetzone(const cred_t *cr)
741{
742	return (cr->cr_zone);
743}
744
745struct ts_label_s *
746crgetlabel(const cred_t *cr)
747{
748	return (cr->cr_label ?
749	    cr->cr_label :
750	    (cr->cr_zone ? cr->cr_zone->zone_slabel : NULL));
751}
752
753boolean_t
754crisremote(const cred_t *cr)
755{
756	return (REMOTE_PEER_CRED(cr));
757}
758
759#define	BADUID(x, zn)	((x) != -1 && !VALID_UID((x), (zn)))
760#define	BADGID(x, zn)	((x) != -1 && !VALID_GID((x), (zn)))
761
762int
763crsetresuid(cred_t *cr, uid_t r, uid_t e, uid_t s)
764{
765	zone_t	*zone = crgetzone(cr);
766
767	ASSERT(cr->cr_ref <= 2);
768
769	if (BADUID(r, zone) || BADUID(e, zone) || BADUID(s, zone))
770		return (-1);
771
772	if (r != -1)
773		cr->cr_ruid = r;
774	if (e != -1)
775		cr->cr_uid = e;
776	if (s != -1)
777		cr->cr_suid = s;
778
779	return (0);
780}
781
782int
783crsetresgid(cred_t *cr, gid_t r, gid_t e, gid_t s)
784{
785	zone_t	*zone = crgetzone(cr);
786
787	ASSERT(cr->cr_ref <= 2);
788
789	if (BADGID(r, zone) || BADGID(e, zone) || BADGID(s, zone))
790		return (-1);
791
792	if (r != -1)
793		cr->cr_rgid = r;
794	if (e != -1)
795		cr->cr_gid = e;
796	if (s != -1)
797		cr->cr_sgid = s;
798
799	return (0);
800}
801
802int
803crsetugid(cred_t *cr, uid_t uid, gid_t gid)
804{
805	zone_t	*zone = crgetzone(cr);
806
807	ASSERT(cr->cr_ref <= 2);
808
809	if (!VALID_UID(uid, zone) || !VALID_GID(gid, zone))
810		return (-1);
811
812	cr->cr_uid = cr->cr_ruid = cr->cr_suid = uid;
813	cr->cr_gid = cr->cr_rgid = cr->cr_sgid = gid;
814
815	return (0);
816}
817
818static int
819gidcmp(const void *v1, const void *v2)
820{
821	gid_t g1 = *(gid_t *)v1;
822	gid_t g2 = *(gid_t *)v2;
823
824	if (g1 < g2)
825		return (-1);
826	else if (g1 > g2)
827		return (1);
828	else
829		return (0);
830}
831
832int
833crsetgroups(cred_t *cr, int n, gid_t *grp)
834{
835	ASSERT(cr->cr_ref <= 2);
836
837	if (n > ngroups_max || n < 0)
838		return (-1);
839
840	if (cr->cr_grps != NULL)
841		crgrprele(cr->cr_grps);
842
843	if (n > 0) {
844		cr->cr_grps = kmem_alloc(CREDGRPSZ(n), KM_SLEEP);
845		bcopy(grp, cr->cr_grps->crg_groups, n * sizeof (gid_t));
846		cr->cr_grps->crg_ref = 1;
847		cr->cr_grps->crg_ngroups = n;
848		qsort(cr->cr_grps->crg_groups, n, sizeof (gid_t), gidcmp);
849	} else {
850		cr->cr_grps = NULL;
851	}
852
853	return (0);
854}
855
856void
857crsetprojid(cred_t *cr, projid_t projid)
858{
859	ASSERT(projid >= 0 && projid <= MAXPROJID);
860	cr->cr_projid = projid;
861}
862
863/*
864 * This routine returns the pointer to the first element of the crg_groups
865 * array.  It can move around in an implementation defined way.
866 * Note that when we have no grouplist, we return one element but the
867 * caller should never reference it.
868 */
869const gid_t *
870crgetgroups(const cred_t *cr)
871{
872	return (cr->cr_grps == NULL ? &cr->cr_gid : cr->cr_grps->crg_groups);
873}
874
875int
876crgetngroups(const cred_t *cr)
877{
878	return (cr->cr_grps == NULL ? 0 : cr->cr_grps->crg_ngroups);
879}
880
881void
882cred2prcred(const cred_t *cr, prcred_t *pcrp)
883{
884	pcrp->pr_euid = cr->cr_uid;
885	pcrp->pr_ruid = cr->cr_ruid;
886	pcrp->pr_suid = cr->cr_suid;
887	pcrp->pr_egid = cr->cr_gid;
888	pcrp->pr_rgid = cr->cr_rgid;
889	pcrp->pr_sgid = cr->cr_sgid;
890	pcrp->pr_groups[0] = 0; /* in case ngroups == 0 */
891	pcrp->pr_ngroups = cr->cr_grps == NULL ? 0 : cr->cr_grps->crg_ngroups;
892
893	if (pcrp->pr_ngroups != 0)
894		bcopy(cr->cr_grps->crg_groups, pcrp->pr_groups,
895		    sizeof (gid_t) * pcrp->pr_ngroups);
896}
897
898static int
899cred2ucaud(const cred_t *cr, auditinfo64_addr_t *ainfo, const cred_t *rcr)
900{
901	auditinfo_addr_t	*ai;
902	au_tid_addr_t	tid;
903
904	if (secpolicy_audit_getattr(rcr, B_TRUE) != 0)
905		return (-1);
906
907	ai = CR_AUINFO(cr);	/* caller makes sure this is non-NULL */
908	tid = ai->ai_termid;
909
910	ainfo->ai_auid = ai->ai_auid;
911	ainfo->ai_mask = ai->ai_mask;
912	ainfo->ai_asid = ai->ai_asid;
913
914	ainfo->ai_termid.at_type = tid.at_type;
915	bcopy(&tid.at_addr, &ainfo->ai_termid.at_addr, 4 * sizeof (uint_t));
916
917	ainfo->ai_termid.at_port.at_major = (uint32_t)getmajor(tid.at_port);
918	ainfo->ai_termid.at_port.at_minor = (uint32_t)getminor(tid.at_port);
919
920	return (0);
921}
922
923void
924cred2uclabel(const cred_t *cr, bslabel_t *labelp)
925{
926	ts_label_t	*tslp;
927
928	if ((tslp = crgetlabel(cr)) != NULL)
929		bcopy(&tslp->tsl_label, labelp, sizeof (bslabel_t));
930}
931
932/*
933 * Convert a credential into a "ucred".  Allow the caller to specify
934 * and aligned buffer, e.g., in an mblk, so we don't have to allocate
935 * memory and copy it twice.
936 *
937 * This function may call cred2ucaud(), which calls CRED(). Since this
938 * can be called from an interrupt thread, receiver's cred (rcr) is needed
939 * to determine whether audit info should be included.
940 */
941struct ucred_s *
942cred2ucred(const cred_t *cr, pid_t pid, void *buf, const cred_t *rcr)
943{
944	struct ucred_s *uc;
945	uint32_t realsz = ucredminsize(cr);
946	ts_label_t *tslp = is_system_labeled() ? crgetlabel(cr) : NULL;
947
948	/* The structure isn't always completely filled in, so zero it */
949	if (buf == NULL) {
950		uc = kmem_zalloc(realsz, KM_SLEEP);
951	} else {
952		bzero(buf, realsz);
953		uc = buf;
954	}
955	uc->uc_size = realsz;
956	uc->uc_pid = pid;
957	uc->uc_projid = cr->cr_projid;
958	uc->uc_zoneid = crgetzoneid(cr);
959
960	if (REMOTE_PEER_CRED(cr)) {
961		/*
962		 * Other than label, the rest of cred info about a
963		 * remote peer isn't available. Copy the label directly
964		 * after the header where we generally copy the prcred.
965		 * That's why we use sizeof (struct ucred_s).  The other
966		 * offset fields are initialized to 0.
967		 */
968		uc->uc_labeloff = tslp == NULL ? 0 : sizeof (struct ucred_s);
969	} else {
970		uc->uc_credoff = UCRED_CRED_OFF;
971		uc->uc_privoff = UCRED_PRIV_OFF;
972		uc->uc_audoff = UCRED_AUD_OFF;
973		uc->uc_labeloff = tslp == NULL ? 0 : UCRED_LABEL_OFF;
974
975		cred2prcred(cr, UCCRED(uc));
976		cred2prpriv(cr, UCPRIV(uc));
977
978		if (audoff == 0 || cred2ucaud(cr, UCAUD(uc), rcr) != 0)
979			uc->uc_audoff = 0;
980	}
981	if (tslp != NULL)
982		bcopy(&tslp->tsl_label, UCLABEL(uc), sizeof (bslabel_t));
983
984	return (uc);
985}
986
987/*
988 * Don't allocate the non-needed group entries.  Note: this function
989 * must match the code in cred2ucred; they must agree about the
990 * minimal size of the ucred.
991 */
992uint32_t
993ucredminsize(const cred_t *cr)
994{
995	int ndiff;
996
997	if (cr == NULL)
998		return (ucredsize);
999
1000	if (REMOTE_PEER_CRED(cr)) {
1001		if (is_system_labeled())
1002			return (sizeof (struct ucred_s) + sizeof (bslabel_t));
1003		else
1004			return (sizeof (struct ucred_s));
1005	}
1006
1007	if (cr->cr_grps == NULL)
1008		ndiff = ngroups_max - 1;	/* Needs one for prcred_t */
1009	else
1010		ndiff = ngroups_max - cr->cr_grps->crg_ngroups;
1011
1012	return (ucredsize - ndiff * sizeof (gid_t));
1013}
1014
1015/*
1016 * Get the "ucred" of a process.
1017 */
1018struct ucred_s *
1019pgetucred(proc_t *p)
1020{
1021	cred_t *cr;
1022	struct ucred_s *uc;
1023
1024	mutex_enter(&p->p_crlock);
1025	cr = p->p_cred;
1026	crhold(cr);
1027	mutex_exit(&p->p_crlock);
1028
1029	uc = cred2ucred(cr, p->p_pid, NULL, CRED());
1030	crfree(cr);
1031
1032	return (uc);
1033}
1034
1035/*
1036 * If the reply status is NFSERR_EACCES, it may be because we are
1037 * root (no root net access).  Check the real uid, if it isn't root
1038 * make that the uid instead and retry the call.
1039 * Private interface for NFS.
1040 */
1041cred_t *
1042crnetadjust(cred_t *cr)
1043{
1044	if (cr->cr_uid == 0 && cr->cr_ruid != 0) {
1045		cr = crdup(cr);
1046		cr->cr_uid = cr->cr_ruid;
1047		return (cr);
1048	}
1049	return (NULL);
1050}
1051
1052/*
1053 * The reference count is of interest when you want to check
1054 * whether it is ok to modify the credential in place.
1055 */
1056uint_t
1057crgetref(const cred_t *cr)
1058{
1059	return (cr->cr_ref);
1060}
1061
1062static int
1063get_c2audit_load(void)
1064{
1065	static int	gotit = 0;
1066	static int	c2audit_load;
1067
1068	if (gotit)
1069		return (c2audit_load);
1070	c2audit_load = 1;		/* set default value once */
1071	if (mod_sysctl(SYS_CHECK_EXCLUDE, "c2audit") != 0)
1072		c2audit_load = 0;
1073	gotit++;
1074
1075	return (c2audit_load);
1076}
1077
1078int
1079get_audit_ucrsize(void)
1080{
1081	return (get_c2audit_load() ? sizeof (auditinfo64_addr_t) : 0);
1082}
1083
1084/*
1085 * Set zone pointer in credential to indicated value.  First adds a
1086 * hold for the new zone, then drops the hold on previous zone (if any).
1087 * This is done in this order in case the old and new zones are the
1088 * same.
1089 */
1090void
1091crsetzone(cred_t *cr, zone_t *zptr)
1092{
1093	zone_t *oldzptr = cr->cr_zone;
1094
1095	ASSERT(cr != kcred);
1096	ASSERT(cr->cr_ref <= 2);
1097	cr->cr_zone = zptr;
1098	zone_cred_hold(zptr);
1099	if (oldzptr)
1100		zone_cred_rele(oldzptr);
1101}
1102
1103/*
1104 * Create a new cred based on the supplied label
1105 */
1106cred_t *
1107newcred_from_bslabel(bslabel_t *blabel, uint32_t doi, int flags)
1108{
1109	ts_label_t *lbl = labelalloc(blabel, doi, flags);
1110	cred_t *cr = NULL;
1111
1112	if (lbl != NULL) {
1113		if ((cr = crdup_flags(dummycr, flags)) != NULL) {
1114			cr->cr_label = lbl;
1115		} else {
1116			label_rele(lbl);
1117		}
1118	}
1119
1120	return (cr);
1121}
1122
1123/*
1124 * Derive a new cred from the existing cred, but with a different label.
1125 * To be used when a cred is being shared, but the label needs to be changed
1126 * by a caller without affecting other users
1127 */
1128cred_t *
1129copycred_from_tslabel(const cred_t *cr, ts_label_t *label, int flags)
1130{
1131	cred_t *newcr = NULL;
1132
1133	if ((newcr = crdup_flags(cr, flags)) != NULL) {
1134		if (newcr->cr_label != NULL)
1135			label_rele(newcr->cr_label);
1136		label_hold(label);
1137		newcr->cr_label = label;
1138	}
1139
1140	return (newcr);
1141}
1142
1143/*
1144 * Derive a new cred from the existing cred, but with a different label.
1145 */
1146cred_t *
1147copycred_from_bslabel(const cred_t *cr, bslabel_t *blabel,
1148    uint32_t doi, int flags)
1149{
1150	ts_label_t *lbl = labelalloc(blabel, doi, flags);
1151	cred_t  *newcr = NULL;
1152
1153	if (lbl != NULL) {
1154		newcr = copycred_from_tslabel(cr, lbl, flags);
1155		label_rele(lbl);
1156	}
1157
1158	return (newcr);
1159}
1160
1161/*
1162 * This function returns a pointer to the kcred-equivalent in the current zone.
1163 */
1164cred_t *
1165zone_kcred(void)
1166{
1167	zone_t *zone;
1168
1169	if ((zone = CRED()->cr_zone) != NULL)
1170		return (zone->zone_kcred);
1171	else
1172		return (kcred);
1173}
1174
1175boolean_t
1176valid_ephemeral_uid(zone_t *zone, uid_t id)
1177{
1178	ephemeral_zsd_t *eph_zsd;
1179	if (id <= IDMAP_WK__MAX_UID)
1180		return (B_TRUE);
1181
1182	eph_zsd = get_ephemeral_zsd(zone);
1183	ASSERT(eph_zsd != NULL);
1184	membar_consumer();
1185	return (id > eph_zsd->min_uid && id <= eph_zsd->last_uid);
1186}
1187
1188boolean_t
1189valid_ephemeral_gid(zone_t *zone, gid_t id)
1190{
1191	ephemeral_zsd_t *eph_zsd;
1192	if (id <= IDMAP_WK__MAX_GID)
1193		return (B_TRUE);
1194
1195	eph_zsd = get_ephemeral_zsd(zone);
1196	ASSERT(eph_zsd != NULL);
1197	membar_consumer();
1198	return (id > eph_zsd->min_gid && id <= eph_zsd->last_gid);
1199}
1200
1201int
1202eph_uid_alloc(zone_t *zone, int flags, uid_t *start, int count)
1203{
1204	ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone);
1205
1206	ASSERT(eph_zsd != NULL);
1207
1208	mutex_enter(&eph_zsd->eph_lock);
1209
1210	/* Test for unsigned integer wrap around */
1211	if (eph_zsd->last_uid + count < eph_zsd->last_uid) {
1212		mutex_exit(&eph_zsd->eph_lock);
1213		return (-1);
1214	}
1215
1216	/* first call or idmap crashed and state corrupted */
1217	if (flags != 0)
1218		eph_zsd->min_uid = eph_zsd->last_uid;
1219
1220	hasephids = B_TRUE;
1221	*start = eph_zsd->last_uid + 1;
1222	atomic_add_32(&eph_zsd->last_uid, count);
1223	mutex_exit(&eph_zsd->eph_lock);
1224	return (0);
1225}
1226
1227int
1228eph_gid_alloc(zone_t *zone, int flags, gid_t *start, int count)
1229{
1230	ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone);
1231
1232	ASSERT(eph_zsd != NULL);
1233
1234	mutex_enter(&eph_zsd->eph_lock);
1235
1236	/* Test for unsigned integer wrap around */
1237	if (eph_zsd->last_gid + count < eph_zsd->last_gid) {
1238		mutex_exit(&eph_zsd->eph_lock);
1239		return (-1);
1240	}
1241
1242	/* first call or idmap crashed and state corrupted */
1243	if (flags != 0)
1244		eph_zsd->min_gid = eph_zsd->last_gid;
1245
1246	hasephids = B_TRUE;
1247	*start = eph_zsd->last_gid + 1;
1248	atomic_add_32(&eph_zsd->last_gid, count);
1249	mutex_exit(&eph_zsd->eph_lock);
1250	return (0);
1251}
1252
1253/*
1254 * IMPORTANT.The two functions get_ephemeral_data() and set_ephemeral_data()
1255 * are project private functions that are for use of the test system only and
1256 * are not to be used for other purposes.
1257 */
1258
1259void
1260get_ephemeral_data(zone_t *zone, uid_t *min_uid, uid_t *last_uid,
1261    gid_t *min_gid, gid_t *last_gid)
1262{
1263	ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone);
1264
1265	ASSERT(eph_zsd != NULL);
1266
1267	mutex_enter(&eph_zsd->eph_lock);
1268
1269	*min_uid = eph_zsd->min_uid;
1270	*last_uid = eph_zsd->last_uid;
1271	*min_gid = eph_zsd->min_gid;
1272	*last_gid = eph_zsd->last_gid;
1273
1274	mutex_exit(&eph_zsd->eph_lock);
1275}
1276
1277
1278void
1279set_ephemeral_data(zone_t *zone, uid_t min_uid, uid_t last_uid,
1280    gid_t min_gid, gid_t last_gid)
1281{
1282	ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone);
1283
1284	ASSERT(eph_zsd != NULL);
1285
1286	mutex_enter(&eph_zsd->eph_lock);
1287
1288	if (min_uid != 0)
1289		eph_zsd->min_uid = min_uid;
1290	if (last_uid != 0)
1291		eph_zsd->last_uid = last_uid;
1292	if (min_gid != 0)
1293		eph_zsd->min_gid = min_gid;
1294	if (last_gid != 0)
1295		eph_zsd->last_gid = last_gid;
1296
1297	mutex_exit(&eph_zsd->eph_lock);
1298}
1299
1300/*
1301 * If the credential user SID or group SID is mapped to an ephemeral
1302 * ID, map the credential to nobody.
1303 */
1304cred_t *
1305crgetmapped(const cred_t *cr)
1306{
1307	ephemeral_zsd_t *eph_zsd;
1308	/*
1309	 * Someone incorrectly passed a NULL cred to a vnode operation
1310	 * either on purpose or by calling CRED() in interrupt context.
1311	 */
1312	if (cr == NULL)
1313		return (NULL);
1314
1315	if (cr->cr_ksid != NULL) {
1316		if (cr->cr_ksid->kr_sidx[KSID_USER].ks_id > MAXUID) {
1317			eph_zsd = get_ephemeral_zsd(crgetzone(cr));
1318			return (eph_zsd->eph_nobody);
1319		}
1320
1321		if (cr->cr_ksid->kr_sidx[KSID_GROUP].ks_id > MAXUID) {
1322			eph_zsd = get_ephemeral_zsd(crgetzone(cr));
1323			return (eph_zsd->eph_nobody);
1324		}
1325	}
1326
1327	return ((cred_t *)cr);
1328}
1329
1330/* index should be in range for a ksidindex_t */
1331void
1332crsetsid(cred_t *cr, ksid_t *ksp, int index)
1333{
1334	ASSERT(cr->cr_ref <= 2);
1335	ASSERT(index >= 0 && index < KSID_COUNT);
1336	if (cr->cr_ksid == NULL && ksp == NULL)
1337		return;
1338	cr->cr_ksid = kcrsid_setsid(cr->cr_ksid, ksp, index);
1339}
1340
1341void
1342crsetsidlist(cred_t *cr, ksidlist_t *ksl)
1343{
1344	ASSERT(cr->cr_ref <= 2);
1345	if (cr->cr_ksid == NULL && ksl == NULL)
1346		return;
1347	cr->cr_ksid = kcrsid_setsidlist(cr->cr_ksid, ksl);
1348}
1349
1350ksid_t *
1351crgetsid(const cred_t *cr, int i)
1352{
1353	ASSERT(i >= 0 && i < KSID_COUNT);
1354	if (cr->cr_ksid != NULL && cr->cr_ksid->kr_sidx[i].ks_domain)
1355		return ((ksid_t *)&cr->cr_ksid->kr_sidx[i]);
1356	return (NULL);
1357}
1358
1359ksidlist_t *
1360crgetsidlist(const cred_t *cr)
1361{
1362	if (cr->cr_ksid != NULL)
1363		return (cr->cr_ksid->kr_sidlist);
1364	return (NULL);
1365}
1366
1367/*
1368 * Interface to set the effective and permitted privileges for
1369 * a credential; this interface does no security checks and is
1370 * intended for kernel (file)servers creating credentials with
1371 * specific privileges.
1372 */
1373int
1374crsetpriv(cred_t *cr, ...)
1375{
1376	va_list ap;
1377	const char *privnm;
1378
1379	ASSERT(cr->cr_ref <= 2);
1380
1381	priv_set_PA(cr);
1382
1383	va_start(ap, cr);
1384
1385	while ((privnm = va_arg(ap, const char *)) != NULL) {
1386		int priv = priv_getbyname(privnm, 0);
1387		if (priv < 0)
1388			return (-1);
1389
1390		priv_addset(&CR_PPRIV(cr), priv);
1391		priv_addset(&CR_EPRIV(cr), priv);
1392	}
1393	priv_adjust_PA(cr);
1394	va_end(ap);
1395	return (0);
1396}
1397
1398/*
1399 * Interface to effectively set the PRIV_ALL for
1400 * a credential; this interface does no security checks and is
1401 * intended for kernel (file)servers to extend the user credentials
1402 * to be ALL, like either kcred or zcred.
1403 */
1404void
1405crset_zone_privall(cred_t *cr)
1406{
1407	zone_t	*zone = crgetzone(cr);
1408
1409	priv_fillset(&CR_LPRIV(cr));
1410	CR_EPRIV(cr) = CR_PPRIV(cr) = CR_IPRIV(cr) = CR_LPRIV(cr);
1411	priv_intersect(zone->zone_privset, &CR_LPRIV(cr));
1412	priv_intersect(zone->zone_privset, &CR_EPRIV(cr));
1413	priv_intersect(zone->zone_privset, &CR_IPRIV(cr));
1414	priv_intersect(zone->zone_privset, &CR_PPRIV(cr));
1415}
1416
1417struct credklpd *
1418crgetcrklpd(const cred_t *cr)
1419{
1420	return (cr->cr_klpd);
1421}
1422
1423void
1424crsetcrklpd(cred_t *cr, struct credklpd *crklpd)
1425{
1426	ASSERT(cr->cr_ref <= 2);
1427
1428	if (cr->cr_klpd != NULL)
1429		crklpd_rele(cr->cr_klpd);
1430	cr->cr_klpd = crklpd;
1431}
1432
1433credgrp_t *
1434crgrpcopyin(int n, gid_t *gidset)
1435{
1436	credgrp_t *mem;
1437	size_t sz = CREDGRPSZ(n);
1438
1439	ASSERT(n > 0);
1440
1441	mem = kmem_alloc(sz, KM_SLEEP);
1442
1443	if (copyin(gidset, mem->crg_groups, sizeof (gid_t) * n)) {
1444		kmem_free(mem, sz);
1445		return (NULL);
1446	}
1447	mem->crg_ref = 1;
1448	mem->crg_ngroups = n;
1449	qsort(mem->crg_groups, n, sizeof (gid_t), gidcmp);
1450	return (mem);
1451}
1452
1453const gid_t *
1454crgetggroups(const credgrp_t *grps)
1455{
1456	return (grps->crg_groups);
1457}
1458
1459void
1460crsetcredgrp(cred_t *cr, credgrp_t *grps)
1461{
1462	ASSERT(cr->cr_ref <= 2);
1463
1464	if (cr->cr_grps != NULL)
1465		crgrprele(cr->cr_grps);
1466
1467	cr->cr_grps = grps;
1468}
1469
1470void
1471crgrprele(credgrp_t *grps)
1472{
1473	if (atomic_dec_32_nv(&grps->crg_ref) == 0)
1474		kmem_free(grps, CREDGRPSZ(grps->crg_ngroups));
1475}
1476
1477static void
1478crgrphold(credgrp_t *grps)
1479{
1480	atomic_inc_32(&grps->crg_ref);
1481}
1482