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