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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <unistd.h> 30 #include <ctype.h> 31 #include <priv.h> 32 #include <string.h> 33 #include <libgen.h> 34 #include <errno.h> 35 #include <libintl.h> 36 #include <sys/devpolicy.h> 37 #include <sys/modctl.h> 38 #include "message.h" 39 #include "plcysubr.h" 40 41 /* Cannot include devfsadm_impl.h because of static definitions */ 42 #define err_print devfsadm_errprint 43 extern void err_print(char *, ...); 44 45 #define PLCY_CHUNK 128 46 47 /* 48 * devpolicy sort order sorts on three items to help the kernel; 49 * the kernel will verify but not sort. 50 * 51 * 1) major number - but default major will be first in sorted output 52 * 2) wildcard or not - non wildcard entries are sorted first. 53 * 2a) Expanded minor numbers first (empty name sorts first). 54 * 2b) Named minors. 55 * 3) length of wildcard entry - longest pattern first 56 * 57 * The last rule allows patterns such as *ctl and * to be used both 58 * unambiguously instead of current bogosities as found in /etc/minor_perm: 59 * rtvc:ctl 0644 root sys 60 * rtvc:rtvcctl* 0644 root sys 61 * rtvc:rtvc[!ctl]* 0666 root sys 62 * 63 * The last pattern only works by accident. 64 * 65 * This would simply become (in sorted order): 66 * rtvc:ctl 67 * rtvc:rtvcctl* 68 * rtvc:* 69 */ 70 71 static int 72 qcmp(const void *a, const void *b) 73 { 74 const devplcysys_t *pa = a; 75 const devplcysys_t *pb = b; 76 int wilda, wildb; 77 78 /* sort on major number, default major first in sort output */ 79 if (pa->dps_maj == DEVPOLICY_DFLT_MAJ) 80 return (-1); 81 if (pb->dps_maj == DEVPOLICY_DFLT_MAJ) 82 return (1); 83 84 if (pa->dps_maj > pb->dps_maj) 85 return (1); 86 else if (pa->dps_maj < pb->dps_maj) 87 return (-1); 88 89 wilda = strchr(pa->dps_minornm, '*') != NULL; 90 wildb = strchr(pb->dps_minornm, '*') != NULL; 91 92 /* sort the entry with the wildcard last */ 93 if (wilda != wildb) 94 return (wilda - wildb); 95 96 /* entries without wildcards compare with strcmp() */ 97 if (wilda == 0) 98 return (strcmp(pa->dps_minornm, pb->dps_minornm)); 99 100 /* shortest wildcard last */ 101 return ((int)(strlen(pb->dps_minornm) - strlen(pa->dps_minornm))); 102 } 103 104 static int 105 loadprivs(const char *infile) 106 { 107 char *line, *col; 108 FILE *in; 109 struct fileentry *fep; 110 int res = 0; 111 112 in = fopen(infile, "r"); 113 114 if (in == NULL) 115 return (0); 116 117 while ((fep = fgetline(in)) != NULL && fep->entry != NULL) { 118 line = fep->entry; 119 120 if (*line == '\0') 121 continue; 122 123 line[strlen(line)-1] = '\0'; 124 125 col = strchr(line, ':'); 126 127 if (col != NULL) { 128 major_t maj; 129 *col = '\0'; 130 131 if (modctl(MODGETMAJBIND, line, col - line + 1, &maj) 132 != 0) 133 continue; 134 135 line = col + 1; 136 } 137 138 if (modctl(MODALLOCPRIV, line) != 0) { 139 (void) err_print("modctl(MODALLOCPRIV, %s): %s\n", 140 line, strerror(errno)); 141 res = -1; 142 } 143 } 144 return (res); 145 } 146 147 static int 148 loadpolicy(const char *infile) 149 { 150 char *line; 151 int nalloc = 0, cnt = 0; 152 char *mem = NULL; 153 devplcysys_t *dp, *dflt = NULL; 154 FILE *in; 155 struct fileentry *fep; 156 int res; 157 158 char *maj; 159 char *tok; 160 char *min; 161 162 in = fopen(infile, "r"); 163 164 if (in == NULL) { 165 err_print(OPEN_FAILED, infile, strerror(errno)); 166 return (-1); 167 } 168 169 while ((fep = fgetline(in)) != NULL && fep->entry != NULL) { 170 line = fep->entry; 171 if (cnt >= nalloc) { 172 nalloc += PLCY_CHUNK; 173 mem = realloc(mem, nalloc * devplcysys_sz); 174 if (mem == NULL) { 175 err_print(MALLOC_FAILED, 176 nalloc * devplcysys_sz); 177 return (-1); 178 } 179 180 /* Readjust pointer to dflt after realloc */ 181 if (dflt != NULL) 182 /* LINTED: alignment */ 183 dflt = (devplcysys_t *)mem; 184 } 185 maj = strtok(line, "\n\t "); 186 187 if (maj == NULL) 188 continue; 189 190 /* LINTED: alignment */ 191 dp = (devplcysys_t *)(mem + devplcysys_sz * cnt); 192 193 if (strcmp(maj, "*") == 0) { 194 if (dflt != NULL) { 195 err_print(DPLCY_ONE_DFLT, infile); 196 return (-1); 197 } 198 (void) memset(dp, 0, devplcysys_sz); 199 dp->dps_maj = DEVPOLICY_DFLT_MAJ; 200 dflt = dp; 201 } else { 202 if (dflt == NULL) { 203 err_print(DPLCY_FIRST, infile); 204 return (-1); 205 } 206 207 (void) memcpy(dp, dflt, devplcysys_sz); 208 209 min = strchr(maj, ':'); 210 211 if (min != NULL) { 212 *min++ = '\0'; 213 if (strchr(min, ':') != NULL) { 214 (void) fprintf(stderr, 215 "Too many ``:'' in entry\n"); 216 return (-1); 217 } 218 } else 219 min = "*"; 220 221 /* Silently ignore unknown devices. */ 222 if (modctl(MODGETMAJBIND, maj, strlen(maj) + 1, 223 &dp->dps_maj) != 0) 224 continue; 225 226 if (*min == '(') { 227 /* Numeric minor range */ 228 char type; 229 230 if (parse_minor_range(min, &dp->dps_lomin, 231 &dp->dps_himin, &type) == -1) { 232 err_print(INVALID_MINOR, min); 233 return (-1); 234 } 235 dp->dps_isblock = type == 'b'; 236 } else { 237 if (strlen(min) >= sizeof (dp->dps_minornm)) { 238 err_print(MINOR_TOO_LONG, maj, min); 239 return (-1); 240 } 241 (void) strcpy(dp->dps_minornm, min); 242 } 243 } 244 245 while (tok = strtok(NULL, "\n\t ")) { 246 if (parse_plcy_token(tok, dp)) { 247 err_print(BAD_ENTRY, fep->startline, 248 fep->orgentry); 249 return (-1); 250 } 251 } 252 cnt++; 253 } 254 if (fep == NULL) { 255 if (feof(in)) 256 err_print(UNEXPECTED_EOF, infile); 257 else 258 err_print(NO_MEMORY); 259 return (-1); 260 } 261 qsort(mem, cnt, devplcysys_sz, qcmp); 262 263 if ((res = modctl(MODSETDEVPOLICY, cnt, devplcysys_sz, mem)) != 0) 264 err_print("modctl(MODSETDEVPOLICY): %s\n", strerror(errno)); 265 266 return (res); 267 } 268 269 int 270 load_devpolicy(void) 271 { 272 int res; 273 274 devplcy_init(); 275 276 res = loadprivs(EXTRA_PRIVS); 277 res += loadpolicy(DEV_POLICY); 278 279 return (res); 280 } 281