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, ©->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