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