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
qcmp(const void * a,const void * b)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
loadprivs(const char * infile)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
loadpolicy(const char * infile)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
load_devpolicy(void)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