xref: /dragonfly/sys/kern/kern_varsym.c (revision 98a7f915)
1*98a7f915SMatthew Dillon /*
2*98a7f915SMatthew Dillon  * Copyright (c) 2003 Matthew Dillon <dillon@backplane.com>
3*98a7f915SMatthew Dillon  * All rights reserved.
4*98a7f915SMatthew Dillon  *
5*98a7f915SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
6*98a7f915SMatthew Dillon  * modification, are permitted provided that the following conditions
7*98a7f915SMatthew Dillon  * are met:
8*98a7f915SMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
9*98a7f915SMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
10*98a7f915SMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
11*98a7f915SMatthew Dillon  *    notice, this list of conditions and the following disclaimer in the
12*98a7f915SMatthew Dillon  *    documentation and/or other materials provided with the distribution.
13*98a7f915SMatthew Dillon  *
14*98a7f915SMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*98a7f915SMatthew Dillon  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*98a7f915SMatthew Dillon  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*98a7f915SMatthew Dillon  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*98a7f915SMatthew Dillon  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*98a7f915SMatthew Dillon  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*98a7f915SMatthew Dillon  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*98a7f915SMatthew Dillon  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*98a7f915SMatthew Dillon  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*98a7f915SMatthew Dillon  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*98a7f915SMatthew Dillon  * SUCH DAMAGE.
25*98a7f915SMatthew Dillon  *
26*98a7f915SMatthew Dillon  * $DragonFly: src/sys/kern/kern_varsym.c,v 1.1 2003/11/05 23:26:20 dillon Exp $
27*98a7f915SMatthew Dillon  */
28*98a7f915SMatthew Dillon 
29*98a7f915SMatthew Dillon /*
30*98a7f915SMatthew Dillon  * This module implements variable storage and management for variant
31*98a7f915SMatthew Dillon  * symlinks.  These variables may also be used for general purposes.
32*98a7f915SMatthew Dillon  */
33*98a7f915SMatthew Dillon 
34*98a7f915SMatthew Dillon #include <sys/param.h>
35*98a7f915SMatthew Dillon #include <sys/systm.h>
36*98a7f915SMatthew Dillon #include <sys/kernel.h>
37*98a7f915SMatthew Dillon #include <sys/ucred.h>
38*98a7f915SMatthew Dillon #include <sys/resourcevar.h>
39*98a7f915SMatthew Dillon #include <sys/proc.h>
40*98a7f915SMatthew Dillon #include <sys/queue.h>
41*98a7f915SMatthew Dillon #include <sys/sysctl.h>
42*98a7f915SMatthew Dillon #include <sys/malloc.h>
43*98a7f915SMatthew Dillon #include <sys/varsym.h>
44*98a7f915SMatthew Dillon #include <sys/sysproto.h>
45*98a7f915SMatthew Dillon 
46*98a7f915SMatthew Dillon MALLOC_DEFINE(M_VARSYM, "varsym", "variable sets for variant symlinks");
47*98a7f915SMatthew Dillon 
48*98a7f915SMatthew Dillon struct varsymset	varsymset_sys;
49*98a7f915SMatthew Dillon 
50*98a7f915SMatthew Dillon /*
51*98a7f915SMatthew Dillon  * Initialize the variant symlink subsystem
52*98a7f915SMatthew Dillon  */
53*98a7f915SMatthew Dillon static void
54*98a7f915SMatthew Dillon varsym_sysinit(void *dummy)
55*98a7f915SMatthew Dillon {
56*98a7f915SMatthew Dillon     varsymset_init(&varsymset_sys, NULL);
57*98a7f915SMatthew Dillon }
58*98a7f915SMatthew Dillon SYSINIT(announce, SI_SUB_INTRINSIC, SI_ORDER_FIRST, varsym_sysinit, NULL);
59*98a7f915SMatthew Dillon 
60*98a7f915SMatthew Dillon /*
61*98a7f915SMatthew Dillon  * varsym_set() system call
62*98a7f915SMatthew Dillon  *
63*98a7f915SMatthew Dillon  * (int level, const char *name, const char *data)
64*98a7f915SMatthew Dillon  */
65*98a7f915SMatthew Dillon int
66*98a7f915SMatthew Dillon varsym_set(struct varsym_set_args *uap)
67*98a7f915SMatthew Dillon {
68*98a7f915SMatthew Dillon     char name[MAXVARSYM_NAME];
69*98a7f915SMatthew Dillon     char *buf;
70*98a7f915SMatthew Dillon     int error;
71*98a7f915SMatthew Dillon 
72*98a7f915SMatthew Dillon     if ((error = copyinstr(uap->name, name, sizeof(name), NULL)) != 0)
73*98a7f915SMatthew Dillon 	goto done2;
74*98a7f915SMatthew Dillon     buf = malloc(MAXVARSYM_DATA, M_TEMP, 0);
75*98a7f915SMatthew Dillon     if (uap->data &&
76*98a7f915SMatthew Dillon 	(error = copyinstr(uap->data, buf, MAXVARSYM_DATA, NULL)) != 0)
77*98a7f915SMatthew Dillon     {
78*98a7f915SMatthew Dillon 	goto done1;
79*98a7f915SMatthew Dillon     }
80*98a7f915SMatthew Dillon     switch(uap->level) {
81*98a7f915SMatthew Dillon     case VARSYM_SYS:
82*98a7f915SMatthew Dillon 	if ((error = suser(curthread)) != 0)
83*98a7f915SMatthew Dillon 	    break;
84*98a7f915SMatthew Dillon 	/* XXX implement per-jail sys */
85*98a7f915SMatthew Dillon 	/* fall through */
86*98a7f915SMatthew Dillon     case VARSYM_USER:
87*98a7f915SMatthew Dillon 	/* XXX check jail / implement per-jail user */
88*98a7f915SMatthew Dillon 	/* fall through */
89*98a7f915SMatthew Dillon     case VARSYM_PROC:
90*98a7f915SMatthew Dillon 	if (uap->data) {
91*98a7f915SMatthew Dillon 	    (void)varsymmake(uap->level, name, NULL);
92*98a7f915SMatthew Dillon 	    error = varsymmake(uap->level, name, buf);
93*98a7f915SMatthew Dillon 	} else {
94*98a7f915SMatthew Dillon 	    error = varsymmake(uap->level, name, NULL);
95*98a7f915SMatthew Dillon 	}
96*98a7f915SMatthew Dillon 	break;
97*98a7f915SMatthew Dillon     }
98*98a7f915SMatthew Dillon done1:
99*98a7f915SMatthew Dillon     free(buf, M_TEMP);
100*98a7f915SMatthew Dillon done2:
101*98a7f915SMatthew Dillon     return(error);
102*98a7f915SMatthew Dillon }
103*98a7f915SMatthew Dillon 
104*98a7f915SMatthew Dillon /*
105*98a7f915SMatthew Dillon  * varsym_get() system call
106*98a7f915SMatthew Dillon  *
107*98a7f915SMatthew Dillon  * (int mask, const char *wild, char *buf, int bufsize)
108*98a7f915SMatthew Dillon  */
109*98a7f915SMatthew Dillon int
110*98a7f915SMatthew Dillon varsym_get(struct varsym_get_args *uap)
111*98a7f915SMatthew Dillon {
112*98a7f915SMatthew Dillon     char wild[MAXVARSYM_NAME];
113*98a7f915SMatthew Dillon     varsym_t sym;
114*98a7f915SMatthew Dillon     int error;
115*98a7f915SMatthew Dillon     int dlen;
116*98a7f915SMatthew Dillon 
117*98a7f915SMatthew Dillon     if ((error = copyinstr(uap->wild, wild, sizeof(wild), NULL)) != 0)
118*98a7f915SMatthew Dillon 	goto done;
119*98a7f915SMatthew Dillon     sym = varsymfind(uap->mask, wild, strlen(wild));
120*98a7f915SMatthew Dillon     if (sym == NULL) {
121*98a7f915SMatthew Dillon 	error = ENOENT;
122*98a7f915SMatthew Dillon 	goto done;
123*98a7f915SMatthew Dillon     }
124*98a7f915SMatthew Dillon     dlen = strlen(sym->vs_data);
125*98a7f915SMatthew Dillon     if (dlen < uap->bufsize) {
126*98a7f915SMatthew Dillon 	copyout(sym->vs_data, uap->buf, dlen + 1);
127*98a7f915SMatthew Dillon     } else if (uap->bufsize) {
128*98a7f915SMatthew Dillon 	copyout("", uap->buf, 1);
129*98a7f915SMatthew Dillon     }
130*98a7f915SMatthew Dillon     uap->sysmsg_result = dlen + 1;
131*98a7f915SMatthew Dillon     varsymdrop(sym);
132*98a7f915SMatthew Dillon done:
133*98a7f915SMatthew Dillon     return(error);
134*98a7f915SMatthew Dillon }
135*98a7f915SMatthew Dillon 
136*98a7f915SMatthew Dillon /*
137*98a7f915SMatthew Dillon  * Lookup a variant symlink.  XXX use a hash table.
138*98a7f915SMatthew Dillon  */
139*98a7f915SMatthew Dillon static
140*98a7f915SMatthew Dillon struct varsyment *
141*98a7f915SMatthew Dillon varsymlookup(struct varsymset *vss, const char *name, int namelen)
142*98a7f915SMatthew Dillon {
143*98a7f915SMatthew Dillon     struct varsyment *ve;
144*98a7f915SMatthew Dillon 
145*98a7f915SMatthew Dillon     TAILQ_FOREACH(ve, &vss->vx_queue, ve_entry) {
146*98a7f915SMatthew Dillon 	varsym_t var = ve->ve_sym;
147*98a7f915SMatthew Dillon 	if (var->vs_namelen == namelen &&
148*98a7f915SMatthew Dillon 	    bcmp(name, var->vs_name, namelen) == 0
149*98a7f915SMatthew Dillon 	) {
150*98a7f915SMatthew Dillon 	    return(ve);
151*98a7f915SMatthew Dillon 	}
152*98a7f915SMatthew Dillon     }
153*98a7f915SMatthew Dillon     return(NULL);
154*98a7f915SMatthew Dillon }
155*98a7f915SMatthew Dillon 
156*98a7f915SMatthew Dillon varsym_t
157*98a7f915SMatthew Dillon varsymfind(int mask, const char *name, int namelen)
158*98a7f915SMatthew Dillon {
159*98a7f915SMatthew Dillon     struct proc *p;
160*98a7f915SMatthew Dillon     struct varsyment *ve = NULL;
161*98a7f915SMatthew Dillon     varsym_t sym;
162*98a7f915SMatthew Dillon 
163*98a7f915SMatthew Dillon     if ((mask & (VARSYM_PROC_MASK|VARSYM_USER_MASK)) && (p = curproc) != NULL) {
164*98a7f915SMatthew Dillon 	if (mask & VARSYM_PROC_MASK)
165*98a7f915SMatthew Dillon 	    ve = varsymlookup(&p->p_varsymset, name, namelen);
166*98a7f915SMatthew Dillon 	if (ve == NULL && (mask & VARSYM_USER_MASK))
167*98a7f915SMatthew Dillon 	    ve = varsymlookup(&p->p_ucred->cr_uidinfo->ui_varsymset, name, namelen);
168*98a7f915SMatthew Dillon     }
169*98a7f915SMatthew Dillon     if (ve == NULL && (mask & VARSYM_SYS_MASK))
170*98a7f915SMatthew Dillon 	ve = varsymlookup(&varsymset_sys, name, namelen);
171*98a7f915SMatthew Dillon     if (ve) {
172*98a7f915SMatthew Dillon 	sym = ve->ve_sym;
173*98a7f915SMatthew Dillon 	++sym->vs_refs;
174*98a7f915SMatthew Dillon 	return(sym);
175*98a7f915SMatthew Dillon     } else {
176*98a7f915SMatthew Dillon 	return(NULL);
177*98a7f915SMatthew Dillon     }
178*98a7f915SMatthew Dillon }
179*98a7f915SMatthew Dillon 
180*98a7f915SMatthew Dillon int
181*98a7f915SMatthew Dillon varsymmake(int level, const char *name, const char *data)
182*98a7f915SMatthew Dillon {
183*98a7f915SMatthew Dillon     struct varsymset *vss = NULL;
184*98a7f915SMatthew Dillon     struct varsyment *ve;
185*98a7f915SMatthew Dillon     struct proc *p = curproc;
186*98a7f915SMatthew Dillon     varsym_t sym;
187*98a7f915SMatthew Dillon     int namelen = strlen(name);
188*98a7f915SMatthew Dillon     int datalen;
189*98a7f915SMatthew Dillon     int error;
190*98a7f915SMatthew Dillon 
191*98a7f915SMatthew Dillon     switch(level) {
192*98a7f915SMatthew Dillon     case VARSYM_PROC:
193*98a7f915SMatthew Dillon 	if (p)
194*98a7f915SMatthew Dillon 	    vss = &p->p_varsymset;
195*98a7f915SMatthew Dillon 	break;
196*98a7f915SMatthew Dillon     case VARSYM_USER:
197*98a7f915SMatthew Dillon 	if (p)
198*98a7f915SMatthew Dillon 	    vss = &p->p_ucred->cr_uidinfo->ui_varsymset;
199*98a7f915SMatthew Dillon 	break;
200*98a7f915SMatthew Dillon     case VARSYM_SYS:
201*98a7f915SMatthew Dillon 	vss = &varsymset_sys;
202*98a7f915SMatthew Dillon 	break;
203*98a7f915SMatthew Dillon     }
204*98a7f915SMatthew Dillon     if (vss == NULL) {
205*98a7f915SMatthew Dillon 	error = EINVAL;
206*98a7f915SMatthew Dillon     } else if (data && vss->vx_setsize >= MAXVARSYM_SET) {
207*98a7f915SMatthew Dillon 	error = E2BIG;
208*98a7f915SMatthew Dillon     } else if (data) {
209*98a7f915SMatthew Dillon 	datalen = strlen(data);
210*98a7f915SMatthew Dillon 	ve = malloc(sizeof(struct varsyment), M_VARSYM, M_ZERO);
211*98a7f915SMatthew Dillon 	sym = malloc(sizeof(struct varsym) + namelen + datalen + 2, M_VARSYM, 0);
212*98a7f915SMatthew Dillon 	ve->ve_sym = sym;
213*98a7f915SMatthew Dillon 	sym->vs_refs = 1;
214*98a7f915SMatthew Dillon 	sym->vs_namelen = namelen;
215*98a7f915SMatthew Dillon 	sym->vs_name = (char *)(sym + 1);
216*98a7f915SMatthew Dillon 	sym->vs_data = sym->vs_name + namelen + 1;
217*98a7f915SMatthew Dillon 	strcpy(sym->vs_name, name);
218*98a7f915SMatthew Dillon 	strcpy(sym->vs_data, data);
219*98a7f915SMatthew Dillon 	TAILQ_INSERT_TAIL(&vss->vx_queue, ve, ve_entry);
220*98a7f915SMatthew Dillon 	vss->vx_setsize += sizeof(struct varsyment) + sizeof(struct varsym) + namelen + datalen + 8;
221*98a7f915SMatthew Dillon 	error = 0;
222*98a7f915SMatthew Dillon     } else {
223*98a7f915SMatthew Dillon 	if ((ve = varsymlookup(vss, name, namelen)) != NULL) {
224*98a7f915SMatthew Dillon 	    TAILQ_REMOVE(&vss->vx_queue, ve, ve_entry);
225*98a7f915SMatthew Dillon 	    vss->vx_setsize -= sizeof(struct varsyment) + sizeof(struct varsym) + namelen + strlen(ve->ve_sym->vs_data) + 8;
226*98a7f915SMatthew Dillon 	    varsymdrop(ve->ve_sym);
227*98a7f915SMatthew Dillon 	    free(ve, M_VARSYM);
228*98a7f915SMatthew Dillon 	    error = 0;
229*98a7f915SMatthew Dillon 	} else {
230*98a7f915SMatthew Dillon 	    error = ENOENT;
231*98a7f915SMatthew Dillon 	}
232*98a7f915SMatthew Dillon     }
233*98a7f915SMatthew Dillon     return(error);
234*98a7f915SMatthew Dillon }
235*98a7f915SMatthew Dillon 
236*98a7f915SMatthew Dillon void
237*98a7f915SMatthew Dillon varsymdrop(varsym_t sym)
238*98a7f915SMatthew Dillon {
239*98a7f915SMatthew Dillon     KKASSERT(sym->vs_refs > 0);
240*98a7f915SMatthew Dillon     if (--sym->vs_refs == 0) {
241*98a7f915SMatthew Dillon 	free(sym, M_VARSYM);
242*98a7f915SMatthew Dillon     }
243*98a7f915SMatthew Dillon }
244*98a7f915SMatthew Dillon 
245*98a7f915SMatthew Dillon static void
246*98a7f915SMatthew Dillon varsymdup(struct varsymset *vss, struct varsyment *ve)
247*98a7f915SMatthew Dillon {
248*98a7f915SMatthew Dillon     struct varsyment *nve;
249*98a7f915SMatthew Dillon 
250*98a7f915SMatthew Dillon     nve = malloc(sizeof(struct varsyment), M_VARSYM, M_ZERO);
251*98a7f915SMatthew Dillon     nve->ve_sym = ve->ve_sym;
252*98a7f915SMatthew Dillon     ++nve->ve_sym->vs_refs;
253*98a7f915SMatthew Dillon     TAILQ_INSERT_TAIL(&vss->vx_queue, nve, ve_entry);
254*98a7f915SMatthew Dillon }
255*98a7f915SMatthew Dillon 
256*98a7f915SMatthew Dillon void
257*98a7f915SMatthew Dillon varsymset_init(struct varsymset *vss, struct varsymset *copy)
258*98a7f915SMatthew Dillon {
259*98a7f915SMatthew Dillon     struct varsyment *ve;
260*98a7f915SMatthew Dillon 
261*98a7f915SMatthew Dillon     TAILQ_INIT(&vss->vx_queue);
262*98a7f915SMatthew Dillon     if (copy) {
263*98a7f915SMatthew Dillon 	TAILQ_FOREACH(ve, &copy->vx_queue, ve_entry) {
264*98a7f915SMatthew Dillon 	    varsymdup(vss, ve);
265*98a7f915SMatthew Dillon 	}
266*98a7f915SMatthew Dillon 	vss->vx_setsize = copy->vx_setsize;
267*98a7f915SMatthew Dillon     }
268*98a7f915SMatthew Dillon }
269*98a7f915SMatthew Dillon 
270*98a7f915SMatthew Dillon void
271*98a7f915SMatthew Dillon varsymset_clean(struct varsymset *vss)
272*98a7f915SMatthew Dillon {
273*98a7f915SMatthew Dillon     struct varsyment *ve;
274*98a7f915SMatthew Dillon 
275*98a7f915SMatthew Dillon     while ((ve = TAILQ_FIRST(&vss->vx_queue)) != NULL) {
276*98a7f915SMatthew Dillon 	TAILQ_REMOVE(&vss->vx_queue, ve, ve_entry);
277*98a7f915SMatthew Dillon 	varsymdrop(ve->ve_sym);
278*98a7f915SMatthew Dillon 	free(ve, M_VARSYM);
279*98a7f915SMatthew Dillon     }
280*98a7f915SMatthew Dillon     vss->vx_setsize = 0;
281*98a7f915SMatthew Dillon }
282*98a7f915SMatthew Dillon 
283