Home | History | Annotate | Download | only in devfsadm
      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