xref: /titanic_53/usr/src/lib/libdevinfo/devinfo_devperm.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #define	_POSIX_PTHREAD_SEMANTICS	/* for readdir_r */
30*7c478bd9Sstevel@tonic-gate #ifdef lint
31*7c478bd9Sstevel@tonic-gate #define	_REENTRANT			/* for strtok_r */
32*7c478bd9Sstevel@tonic-gate #endif
33*7c478bd9Sstevel@tonic-gate 
34*7c478bd9Sstevel@tonic-gate #include <stdio.h>
35*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
36*7c478bd9Sstevel@tonic-gate #include <string.h>
37*7c478bd9Sstevel@tonic-gate #include <unistd.h>
38*7c478bd9Sstevel@tonic-gate #include <dirent.h>
39*7c478bd9Sstevel@tonic-gate #include <errno.h>
40*7c478bd9Sstevel@tonic-gate #include <grp.h>
41*7c478bd9Sstevel@tonic-gate #include <pwd.h>
42*7c478bd9Sstevel@tonic-gate #include <alloca.h>
43*7c478bd9Sstevel@tonic-gate #include <nss_dbdefs.h>
44*7c478bd9Sstevel@tonic-gate #include <stdarg.h>
45*7c478bd9Sstevel@tonic-gate #include <syslog.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/acl.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
50*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
51*7c478bd9Sstevel@tonic-gate #include <sys/devinfo_impl.h>
52*7c478bd9Sstevel@tonic-gate #include <sys/hwconf.h>
53*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
54*7c478bd9Sstevel@tonic-gate #include <libnvpair.h>
55*7c478bd9Sstevel@tonic-gate #include <device_info.h>
56*7c478bd9Sstevel@tonic-gate #include <regex.h>
57*7c478bd9Sstevel@tonic-gate #include <strings.h>
58*7c478bd9Sstevel@tonic-gate #include <libdevinfo.h>
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate extern int is_minor_node(const char *, const char **);
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate static int logindevperm(const char *, uid_t, gid_t, void (*)());
63*7c478bd9Sstevel@tonic-gate static int dir_dev_acc(char *, char *, uid_t, gid_t, mode_t, char *line,
64*7c478bd9Sstevel@tonic-gate 	void (*)());
65*7c478bd9Sstevel@tonic-gate static int setdevaccess(char *, uid_t, gid_t, mode_t, void (*)());
66*7c478bd9Sstevel@tonic-gate static void logerror(char *);
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate #define	MAX_LINELEN	256
69*7c478bd9Sstevel@tonic-gate #define	LOGINDEVPERM	"/etc/logindevperm"
70*7c478bd9Sstevel@tonic-gate #define	DIRWILD		"/*"			/* directory wildcard */
71*7c478bd9Sstevel@tonic-gate #define	DIRWLDLEN	2			/* strlen(DIRWILD) */
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate /*
74*7c478bd9Sstevel@tonic-gate  * Revoke all access to a device node and make sure that there are
75*7c478bd9Sstevel@tonic-gate  * no interposed streams devices attached.  Must be called before a
76*7c478bd9Sstevel@tonic-gate  * device is actually opened.
77*7c478bd9Sstevel@tonic-gate  * When fdetach is called, the underlying device node is revealed; it
78*7c478bd9Sstevel@tonic-gate  * will have the previous owner and that owner can re-attach; so we
79*7c478bd9Sstevel@tonic-gate  * retry until we win.
80*7c478bd9Sstevel@tonic-gate  * Ignore non-existent devices.
81*7c478bd9Sstevel@tonic-gate  */
82*7c478bd9Sstevel@tonic-gate static int
83*7c478bd9Sstevel@tonic-gate setdevaccess(char *dev, uid_t uid, gid_t gid, mode_t mode,
84*7c478bd9Sstevel@tonic-gate     void (*errmsg)(char *))
85*7c478bd9Sstevel@tonic-gate {
86*7c478bd9Sstevel@tonic-gate 	int err = 0, local_errno;
87*7c478bd9Sstevel@tonic-gate 	aclent_t acls[4];
88*7c478bd9Sstevel@tonic-gate 	char errstring[MAX_LINELEN];
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate 	if (chown(dev, uid, gid) == -1) {
91*7c478bd9Sstevel@tonic-gate 		if (errno == ENOENT)	/* no such file */
92*7c478bd9Sstevel@tonic-gate 			return (0);
93*7c478bd9Sstevel@tonic-gate 		err = -1;
94*7c478bd9Sstevel@tonic-gate 	}
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate 	while (fdetach(dev) == 0) {
97*7c478bd9Sstevel@tonic-gate 		if (chown(dev, uid, gid) == -1) {
98*7c478bd9Sstevel@tonic-gate 			err = -1;
99*7c478bd9Sstevel@tonic-gate 			local_errno = errno;
100*7c478bd9Sstevel@tonic-gate 		}
101*7c478bd9Sstevel@tonic-gate 	}
102*7c478bd9Sstevel@tonic-gate 	if (err && errmsg) {
103*7c478bd9Sstevel@tonic-gate 		(void) snprintf(errstring, MAX_LINELEN,
104*7c478bd9Sstevel@tonic-gate 		    "failed to chown device %s: %s\n",
105*7c478bd9Sstevel@tonic-gate 		    dev, strerror(local_errno));
106*7c478bd9Sstevel@tonic-gate 		(*errmsg)(errstring);
107*7c478bd9Sstevel@tonic-gate 	}
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate 	acls[0].a_type = USER_OBJ;
110*7c478bd9Sstevel@tonic-gate 	acls[0].a_id = uid;
111*7c478bd9Sstevel@tonic-gate 	acls[0].a_perm = ((mode & 0700) >> 6);
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate 	acls[1].a_type = GROUP_OBJ;
114*7c478bd9Sstevel@tonic-gate 	acls[1].a_id = gid;
115*7c478bd9Sstevel@tonic-gate 	acls[1].a_perm = ((mode & 0070) >> 3);
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate 	acls[2].a_type = CLASS_OBJ;
118*7c478bd9Sstevel@tonic-gate 	acls[2].a_id = (uid_t)-1;
119*7c478bd9Sstevel@tonic-gate 	acls[2].a_perm = ((mode & 0070) >> 3);
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate 	acls[3].a_type = OTHER_OBJ;
122*7c478bd9Sstevel@tonic-gate 	acls[3].a_id = (uid_t)-1;
123*7c478bd9Sstevel@tonic-gate 	acls[3].a_perm = (mode & 0007);
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate 	/* Remove ACLs */
126*7c478bd9Sstevel@tonic-gate 	if (acl(dev, SETACL, 4, acls) < 0) {
127*7c478bd9Sstevel@tonic-gate 		/*
128*7c478bd9Sstevel@tonic-gate 		 * If the file system returned ENOSYS, we know that it
129*7c478bd9Sstevel@tonic-gate 		 * doesn't support ACLs, therefore, we must assume that
130*7c478bd9Sstevel@tonic-gate 		 * there were no ACLs to remove in the first place.
131*7c478bd9Sstevel@tonic-gate 		 */
132*7c478bd9Sstevel@tonic-gate 		if (errno != ENOSYS) {
133*7c478bd9Sstevel@tonic-gate 			err = -1;
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate 			if (errmsg) {
136*7c478bd9Sstevel@tonic-gate 				(void) snprintf(errstring, MAX_LINELEN,
137*7c478bd9Sstevel@tonic-gate 				    "failed to set acl on device %s: %s\n",
138*7c478bd9Sstevel@tonic-gate 				    dev, strerror(errno));
139*7c478bd9Sstevel@tonic-gate 				(*errmsg)(errstring);
140*7c478bd9Sstevel@tonic-gate 			}
141*7c478bd9Sstevel@tonic-gate 		}
142*7c478bd9Sstevel@tonic-gate 	}
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate 	if (chmod(dev, mode) == -1) {
145*7c478bd9Sstevel@tonic-gate 		err = -1;
146*7c478bd9Sstevel@tonic-gate 		if (errmsg) {
147*7c478bd9Sstevel@tonic-gate 			(void) snprintf(errstring, MAX_LINELEN,
148*7c478bd9Sstevel@tonic-gate 			    "failed to chmod device %s: %s\n",
149*7c478bd9Sstevel@tonic-gate 			    dev, strerror(errno));
150*7c478bd9Sstevel@tonic-gate 			(*errmsg)(errstring);
151*7c478bd9Sstevel@tonic-gate 		}
152*7c478bd9Sstevel@tonic-gate 	}
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate 	return (err);
155*7c478bd9Sstevel@tonic-gate }
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate /*
158*7c478bd9Sstevel@tonic-gate  * logindevperm - change owner/group/permissions of devices
159*7c478bd9Sstevel@tonic-gate  * list in /etc/logindevperm.
160*7c478bd9Sstevel@tonic-gate  */
161*7c478bd9Sstevel@tonic-gate static int
162*7c478bd9Sstevel@tonic-gate logindevperm(const char *ttyn, uid_t uid, gid_t gid, void (*errmsg)(char *))
163*7c478bd9Sstevel@tonic-gate {
164*7c478bd9Sstevel@tonic-gate 	int err = 0, lineno = 0;
165*7c478bd9Sstevel@tonic-gate 	const char *field_delims = " \t\n";
166*7c478bd9Sstevel@tonic-gate 	char line[MAX_LINELEN], errstring[MAX_LINELEN];
167*7c478bd9Sstevel@tonic-gate 	char saveline[MAX_LINELEN];
168*7c478bd9Sstevel@tonic-gate 	char *console;
169*7c478bd9Sstevel@tonic-gate 	char *mode_str;
170*7c478bd9Sstevel@tonic-gate 	char *dev_list;
171*7c478bd9Sstevel@tonic-gate 	char *device;
172*7c478bd9Sstevel@tonic-gate 	char *ptr;
173*7c478bd9Sstevel@tonic-gate 	int mode;
174*7c478bd9Sstevel@tonic-gate 	FILE *fp;
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate 	if ((fp = fopen(LOGINDEVPERM, "r")) == NULL) {
177*7c478bd9Sstevel@tonic-gate 		if (errmsg) {
178*7c478bd9Sstevel@tonic-gate 			(void) snprintf(errstring, MAX_LINELEN,
179*7c478bd9Sstevel@tonic-gate 			    LOGINDEVPERM ": open failed: %s\n",
180*7c478bd9Sstevel@tonic-gate 			    strerror(errno));
181*7c478bd9Sstevel@tonic-gate 			(*errmsg)(errstring);
182*7c478bd9Sstevel@tonic-gate 		}
183*7c478bd9Sstevel@tonic-gate 		return (-1);
184*7c478bd9Sstevel@tonic-gate 	}
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate 	while (fgets(line, MAX_LINELEN, fp) != NULL) {
187*7c478bd9Sstevel@tonic-gate 		char *last;
188*7c478bd9Sstevel@tonic-gate 		lineno++;
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate 		if ((ptr = strchr(line, '#')) != NULL)
191*7c478bd9Sstevel@tonic-gate 			*ptr = '\0';	/* handle comments */
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate 		(void) strcpy(saveline, line);
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate 		console = strtok_r(line, field_delims, &last);
196*7c478bd9Sstevel@tonic-gate 		if (console == NULL)
197*7c478bd9Sstevel@tonic-gate 			continue;	/* ignore blank lines */
198*7c478bd9Sstevel@tonic-gate 
199*7c478bd9Sstevel@tonic-gate 		if (strcmp(console, ttyn) != 0)
200*7c478bd9Sstevel@tonic-gate 			continue;	/* not our tty, skip */
201*7c478bd9Sstevel@tonic-gate 
202*7c478bd9Sstevel@tonic-gate 		mode_str = strtok_r(last, field_delims, &last);
203*7c478bd9Sstevel@tonic-gate 		if (mode_str == NULL) {
204*7c478bd9Sstevel@tonic-gate 			err = -1;	/* invalid entry, skip */
205*7c478bd9Sstevel@tonic-gate 			if (errmsg) {
206*7c478bd9Sstevel@tonic-gate 				(void) snprintf(errstring, MAX_LINELEN,
207*7c478bd9Sstevel@tonic-gate 				    LOGINDEVPERM
208*7c478bd9Sstevel@tonic-gate 				    ": line %d, invalid entry -- %s\n",
209*7c478bd9Sstevel@tonic-gate 				    lineno, line);
210*7c478bd9Sstevel@tonic-gate 				(*errmsg)(errstring);
211*7c478bd9Sstevel@tonic-gate 			}
212*7c478bd9Sstevel@tonic-gate 			continue;
213*7c478bd9Sstevel@tonic-gate 		}
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate 		/* convert string to octal value */
216*7c478bd9Sstevel@tonic-gate 		mode = strtol(mode_str, &ptr, 8);
217*7c478bd9Sstevel@tonic-gate 		if (mode < 0 || mode > 0777 || *ptr != '\0') {
218*7c478bd9Sstevel@tonic-gate 			err = -1;	/* invalid mode, skip */
219*7c478bd9Sstevel@tonic-gate 			if (errmsg) {
220*7c478bd9Sstevel@tonic-gate 				(void) snprintf(errstring, MAX_LINELEN,
221*7c478bd9Sstevel@tonic-gate 				    LOGINDEVPERM
222*7c478bd9Sstevel@tonic-gate 				    ": line %d, invalid mode -- %s\n",
223*7c478bd9Sstevel@tonic-gate 				    lineno, mode_str);
224*7c478bd9Sstevel@tonic-gate 				(*errmsg)(errstring);
225*7c478bd9Sstevel@tonic-gate 			}
226*7c478bd9Sstevel@tonic-gate 			continue;
227*7c478bd9Sstevel@tonic-gate 		}
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate 		dev_list = strtok_r(last, field_delims, &last);
230*7c478bd9Sstevel@tonic-gate 		if (dev_list == NULL) {
231*7c478bd9Sstevel@tonic-gate 			err = -1;	/* empty device list, skip */
232*7c478bd9Sstevel@tonic-gate 			if (errmsg) {
233*7c478bd9Sstevel@tonic-gate 				(void) snprintf(errstring, MAX_LINELEN,
234*7c478bd9Sstevel@tonic-gate 				    LOGINDEVPERM
235*7c478bd9Sstevel@tonic-gate 				    ": line %d, empty device list -- %s\n",
236*7c478bd9Sstevel@tonic-gate 				    lineno, line);
237*7c478bd9Sstevel@tonic-gate 				(*errmsg)(errstring);
238*7c478bd9Sstevel@tonic-gate 			}
239*7c478bd9Sstevel@tonic-gate 			continue;
240*7c478bd9Sstevel@tonic-gate 		}
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate 		device = strtok_r(dev_list, ":", &last);
243*7c478bd9Sstevel@tonic-gate 		while (device != NULL) {
244*7c478bd9Sstevel@tonic-gate 			if ((device[0] != '/') || (strlen(device) <= 1))  {
245*7c478bd9Sstevel@tonic-gate 				err = -1;
246*7c478bd9Sstevel@tonic-gate 			} else if (dir_dev_acc("/", &device[1], uid, gid, mode,
247*7c478bd9Sstevel@tonic-gate 			    saveline, errmsg)) {
248*7c478bd9Sstevel@tonic-gate 				err = -1;
249*7c478bd9Sstevel@tonic-gate 			}
250*7c478bd9Sstevel@tonic-gate 			device = strtok_r(last, ":", &last);
251*7c478bd9Sstevel@tonic-gate 		}
252*7c478bd9Sstevel@tonic-gate 	}
253*7c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
254*7c478bd9Sstevel@tonic-gate 	return (err);
255*7c478bd9Sstevel@tonic-gate }
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate /*
258*7c478bd9Sstevel@tonic-gate  * returns 0 if resolved, -1 otherwise.
259*7c478bd9Sstevel@tonic-gate  * devpath: Absolute path to /dev link
260*7c478bd9Sstevel@tonic-gate  * devfs_path: Returns malloced string: /devices path w/out "/devices"
261*7c478bd9Sstevel@tonic-gate  */
262*7c478bd9Sstevel@tonic-gate static int
263*7c478bd9Sstevel@tonic-gate resolve_link(char *devpath, char **devfs_path)
264*7c478bd9Sstevel@tonic-gate {
265*7c478bd9Sstevel@tonic-gate 	char contents[PATH_MAX + 1];
266*7c478bd9Sstevel@tonic-gate 	char stage_link[PATH_MAX + 1];
267*7c478bd9Sstevel@tonic-gate 	char *ptr;
268*7c478bd9Sstevel@tonic-gate 	int linksize;
269*7c478bd9Sstevel@tonic-gate 	char *slashdev = "/dev/";
270*7c478bd9Sstevel@tonic-gate 
271*7c478bd9Sstevel@tonic-gate 	if (devfs_path) {
272*7c478bd9Sstevel@tonic-gate 		*devfs_path = NULL;
273*7c478bd9Sstevel@tonic-gate 	}
274*7c478bd9Sstevel@tonic-gate 
275*7c478bd9Sstevel@tonic-gate 	linksize = readlink(devpath, contents, PATH_MAX);
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate 	if (linksize <= 0) {
278*7c478bd9Sstevel@tonic-gate 		return (-1);
279*7c478bd9Sstevel@tonic-gate 	} else {
280*7c478bd9Sstevel@tonic-gate 		contents[linksize] = '\0';
281*7c478bd9Sstevel@tonic-gate 	}
282*7c478bd9Sstevel@tonic-gate 
283*7c478bd9Sstevel@tonic-gate 	/*
284*7c478bd9Sstevel@tonic-gate 	 * if the link contents is not a minor node assume
285*7c478bd9Sstevel@tonic-gate 	 * that link contents is really a pointer to another
286*7c478bd9Sstevel@tonic-gate 	 * link, and if so recurse and read its link contents.
287*7c478bd9Sstevel@tonic-gate 	 */
288*7c478bd9Sstevel@tonic-gate 	if (is_minor_node((const char *)contents, (const char **)&ptr) !=
289*7c478bd9Sstevel@tonic-gate 	    1) {
290*7c478bd9Sstevel@tonic-gate 		if (strncmp(contents, slashdev, strlen(slashdev)) == 0)  {
291*7c478bd9Sstevel@tonic-gate 			/* absolute path, starting with /dev */
292*7c478bd9Sstevel@tonic-gate 			(void) strcpy(stage_link, contents);
293*7c478bd9Sstevel@tonic-gate 		} else {
294*7c478bd9Sstevel@tonic-gate 			/* relative path, prefix devpath */
295*7c478bd9Sstevel@tonic-gate 			if ((ptr = strrchr(devpath, '/')) == NULL) {
296*7c478bd9Sstevel@tonic-gate 				/* invalid link */
297*7c478bd9Sstevel@tonic-gate 				return (-1);
298*7c478bd9Sstevel@tonic-gate 			}
299*7c478bd9Sstevel@tonic-gate 			*ptr = '\0';
300*7c478bd9Sstevel@tonic-gate 			(void) strcpy(stage_link, devpath);
301*7c478bd9Sstevel@tonic-gate 			*ptr = '/';
302*7c478bd9Sstevel@tonic-gate 			(void) strcat(stage_link, "/");
303*7c478bd9Sstevel@tonic-gate 			(void) strcat(stage_link, contents);
304*7c478bd9Sstevel@tonic-gate 
305*7c478bd9Sstevel@tonic-gate 		}
306*7c478bd9Sstevel@tonic-gate 		return (resolve_link(stage_link, devfs_path));
307*7c478bd9Sstevel@tonic-gate 	}
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate 	if (devfs_path) {
310*7c478bd9Sstevel@tonic-gate 		*devfs_path = strdup(ptr);
311*7c478bd9Sstevel@tonic-gate 		if (*devfs_path == NULL) {
312*7c478bd9Sstevel@tonic-gate 			return (-1);
313*7c478bd9Sstevel@tonic-gate 		}
314*7c478bd9Sstevel@tonic-gate 	}
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate 	return (0);
317*7c478bd9Sstevel@tonic-gate }
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate /*
320*7c478bd9Sstevel@tonic-gate  * check a logindevperm line for a driver list and match this against
321*7c478bd9Sstevel@tonic-gate  * the driver of the minor node
322*7c478bd9Sstevel@tonic-gate  * returns 0 if no drivers were specified or a driver match
323*7c478bd9Sstevel@tonic-gate  */
324*7c478bd9Sstevel@tonic-gate static int
325*7c478bd9Sstevel@tonic-gate check_driver_match(char *path, char *line)
326*7c478bd9Sstevel@tonic-gate {
327*7c478bd9Sstevel@tonic-gate 	char *drv, *driver, *lasts;
328*7c478bd9Sstevel@tonic-gate 	char *devfs_path = NULL;
329*7c478bd9Sstevel@tonic-gate 	char saveline[MAX_LINELEN];
330*7c478bd9Sstevel@tonic-gate 	char *p;
331*7c478bd9Sstevel@tonic-gate 
332*7c478bd9Sstevel@tonic-gate 	if (resolve_link(path, &devfs_path) == 0) {
333*7c478bd9Sstevel@tonic-gate 		char *p;
334*7c478bd9Sstevel@tonic-gate 		char pwd_buf[PATH_MAX];
335*7c478bd9Sstevel@tonic-gate 		di_node_t node;
336*7c478bd9Sstevel@tonic-gate 
337*7c478bd9Sstevel@tonic-gate 		/* truncate on : so we can take a snapshot */
338*7c478bd9Sstevel@tonic-gate 		(void) strcpy(pwd_buf, devfs_path);
339*7c478bd9Sstevel@tonic-gate 		p = strrchr(pwd_buf, ':');
340*7c478bd9Sstevel@tonic-gate 		*p = '\0';
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate 		node = di_init(pwd_buf, DINFOMINOR);
343*7c478bd9Sstevel@tonic-gate 		free(devfs_path);
344*7c478bd9Sstevel@tonic-gate 
345*7c478bd9Sstevel@tonic-gate 		if (node) {
346*7c478bd9Sstevel@tonic-gate 			drv = di_driver_name(node);
347*7c478bd9Sstevel@tonic-gate 			di_fini(node);
348*7c478bd9Sstevel@tonic-gate 		} else {
349*7c478bd9Sstevel@tonic-gate 			return (0);
350*7c478bd9Sstevel@tonic-gate 		}
351*7c478bd9Sstevel@tonic-gate 	} else {
352*7c478bd9Sstevel@tonic-gate 		return (0);
353*7c478bd9Sstevel@tonic-gate 	}
354*7c478bd9Sstevel@tonic-gate 
355*7c478bd9Sstevel@tonic-gate 	(void) strcpy(saveline, line);
356*7c478bd9Sstevel@tonic-gate 
357*7c478bd9Sstevel@tonic-gate 	p = strstr(saveline, "driver");
358*7c478bd9Sstevel@tonic-gate 	if (p == NULL) {
359*7c478bd9Sstevel@tonic-gate 		return (0);
360*7c478bd9Sstevel@tonic-gate 	}
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate 	driver = strtok_r(p, "=", &lasts);
363*7c478bd9Sstevel@tonic-gate 	if (driver) {
364*7c478bd9Sstevel@tonic-gate 		if (strcmp(driver, "driver") == 0) {
365*7c478bd9Sstevel@tonic-gate 			driver = strtok_r(NULL, ", \t\n", &lasts);
366*7c478bd9Sstevel@tonic-gate 			while (driver) {
367*7c478bd9Sstevel@tonic-gate 				if (strcmp(driver, drv) == 0) {
368*7c478bd9Sstevel@tonic-gate 					return (0);
369*7c478bd9Sstevel@tonic-gate 				}
370*7c478bd9Sstevel@tonic-gate 				driver = strtok_r(NULL, ", \t\n", &lasts);
371*7c478bd9Sstevel@tonic-gate 			}
372*7c478bd9Sstevel@tonic-gate 		}
373*7c478bd9Sstevel@tonic-gate 	}
374*7c478bd9Sstevel@tonic-gate 
375*7c478bd9Sstevel@tonic-gate 	return (-1);
376*7c478bd9Sstevel@tonic-gate }
377*7c478bd9Sstevel@tonic-gate 
378*7c478bd9Sstevel@tonic-gate /*
379*7c478bd9Sstevel@tonic-gate  * Apply owner/group/perms to all files (except "." and "..")
380*7c478bd9Sstevel@tonic-gate  * in a directory.
381*7c478bd9Sstevel@tonic-gate  * This function is recursive. We start with "/" and the rest of the pathname
382*7c478bd9Sstevel@tonic-gate  * in left_to_do argument, and we walk the entire pathname which may contain
383*7c478bd9Sstevel@tonic-gate  * regular expressions or '*' for each directory name or basename.
384*7c478bd9Sstevel@tonic-gate  */
385*7c478bd9Sstevel@tonic-gate static int
386*7c478bd9Sstevel@tonic-gate dir_dev_acc(char *path, char *left_to_do, uid_t uid, gid_t gid, mode_t mode,
387*7c478bd9Sstevel@tonic-gate     char *line, void (*errmsg)(char *))
388*7c478bd9Sstevel@tonic-gate {
389*7c478bd9Sstevel@tonic-gate 	struct stat stat_buf;
390*7c478bd9Sstevel@tonic-gate 	int err = 0;
391*7c478bd9Sstevel@tonic-gate 	DIR *dirp;
392*7c478bd9Sstevel@tonic-gate 	struct dirent *direntp, *result;
393*7c478bd9Sstevel@tonic-gate 
394*7c478bd9Sstevel@tonic-gate 	/* path must be a valid name */
395*7c478bd9Sstevel@tonic-gate 	if (stat(path, &stat_buf) == -1) {
396*7c478bd9Sstevel@tonic-gate 		return (-1);
397*7c478bd9Sstevel@tonic-gate 	} else {
398*7c478bd9Sstevel@tonic-gate 		if (!S_ISDIR(stat_buf.st_mode)) {
399*7c478bd9Sstevel@tonic-gate 			if (strlen(left_to_do) == 0) {
400*7c478bd9Sstevel@tonic-gate 				/* finally check the driver matches */
401*7c478bd9Sstevel@tonic-gate 				if (check_driver_match(path, line) == 0) {
402*7c478bd9Sstevel@tonic-gate 					/* we are done, set the permissions */
403*7c478bd9Sstevel@tonic-gate 					if (setdevaccess(path,
404*7c478bd9Sstevel@tonic-gate 					    uid, gid, mode, errmsg)) {
405*7c478bd9Sstevel@tonic-gate 
406*7c478bd9Sstevel@tonic-gate 						return (-1);
407*7c478bd9Sstevel@tonic-gate 					}
408*7c478bd9Sstevel@tonic-gate 				}
409*7c478bd9Sstevel@tonic-gate 			}
410*7c478bd9Sstevel@tonic-gate 			return (0);
411*7c478bd9Sstevel@tonic-gate 		}
412*7c478bd9Sstevel@tonic-gate 	}
413*7c478bd9Sstevel@tonic-gate 
414*7c478bd9Sstevel@tonic-gate 	dirp = opendir(path);
415*7c478bd9Sstevel@tonic-gate 	if (dirp == NULL) {
416*7c478bd9Sstevel@tonic-gate 		return (0);
417*7c478bd9Sstevel@tonic-gate 	} else {
418*7c478bd9Sstevel@tonic-gate 		char *p = strchr(left_to_do, '/');
419*7c478bd9Sstevel@tonic-gate 		regex_t regex;
420*7c478bd9Sstevel@tonic-gate 		int alwaysmatch = 0;
421*7c478bd9Sstevel@tonic-gate 		char *match;
422*7c478bd9Sstevel@tonic-gate 		char *name, *newpath, *remainder_path;
423*7c478bd9Sstevel@tonic-gate 
424*7c478bd9Sstevel@tonic-gate 		newpath = (char *)malloc(MAXPATHLEN);
425*7c478bd9Sstevel@tonic-gate 		if (newpath == NULL) {
426*7c478bd9Sstevel@tonic-gate 			return (-1);
427*7c478bd9Sstevel@tonic-gate 		}
428*7c478bd9Sstevel@tonic-gate 		match = (char *)calloc(MAXPATHLEN, 1);
429*7c478bd9Sstevel@tonic-gate 		if (match == NULL) {
430*7c478bd9Sstevel@tonic-gate 			free(newpath);
431*7c478bd9Sstevel@tonic-gate 			return (-1);
432*7c478bd9Sstevel@tonic-gate 		}
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate 		if (p) {
435*7c478bd9Sstevel@tonic-gate 			(void) strncpy(match, left_to_do, p - left_to_do);
436*7c478bd9Sstevel@tonic-gate 		} else {
437*7c478bd9Sstevel@tonic-gate 			(void) strcpy(match, left_to_do);
438*7c478bd9Sstevel@tonic-gate 		}
439*7c478bd9Sstevel@tonic-gate 
440*7c478bd9Sstevel@tonic-gate 		if (strcmp(match, "*") == 0) {
441*7c478bd9Sstevel@tonic-gate 			alwaysmatch = 1;
442*7c478bd9Sstevel@tonic-gate 		} else {
443*7c478bd9Sstevel@tonic-gate 			if (regcomp(&regex, match, REG_EXTENDED) != 0) {
444*7c478bd9Sstevel@tonic-gate 				free(newpath);
445*7c478bd9Sstevel@tonic-gate 				free(match);
446*7c478bd9Sstevel@tonic-gate 				return (-1);
447*7c478bd9Sstevel@tonic-gate 			}
448*7c478bd9Sstevel@tonic-gate 		}
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 		direntp = alloca(sizeof (struct dirent) + MAXPATHLEN);
451*7c478bd9Sstevel@tonic-gate 		while (readdir_r(dirp, direntp, &result) == 0) {
452*7c478bd9Sstevel@tonic-gate 			if (result == NULL)
453*7c478bd9Sstevel@tonic-gate 				break;
454*7c478bd9Sstevel@tonic-gate 
455*7c478bd9Sstevel@tonic-gate 			name = direntp->d_name;
456*7c478bd9Sstevel@tonic-gate 			if ((strcmp(name, ".") == 0) ||
457*7c478bd9Sstevel@tonic-gate 			    (strcmp(name, "..") == 0))
458*7c478bd9Sstevel@tonic-gate 				continue;
459*7c478bd9Sstevel@tonic-gate 
460*7c478bd9Sstevel@tonic-gate 			if (alwaysmatch ||
461*7c478bd9Sstevel@tonic-gate 			    regexec(&regex, name, 0, NULL, 0) == 0) {
462*7c478bd9Sstevel@tonic-gate 				if (strcmp(path, "/") == 0) {
463*7c478bd9Sstevel@tonic-gate 					(void) snprintf(newpath,
464*7c478bd9Sstevel@tonic-gate 					    MAXPATHLEN, "%s%s", path, name);
465*7c478bd9Sstevel@tonic-gate 				} else {
466*7c478bd9Sstevel@tonic-gate 					(void) snprintf(newpath,
467*7c478bd9Sstevel@tonic-gate 					    MAXPATHLEN, "%s/%s", path, name);
468*7c478bd9Sstevel@tonic-gate 				}
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate 				/*
471*7c478bd9Sstevel@tonic-gate 				 * recurse but adjust what is still left to do
472*7c478bd9Sstevel@tonic-gate 				 */
473*7c478bd9Sstevel@tonic-gate 				remainder_path = (p ?
474*7c478bd9Sstevel@tonic-gate 				    left_to_do + (p - left_to_do) + 1 :
475*7c478bd9Sstevel@tonic-gate 				    &left_to_do[strlen(left_to_do)]);
476*7c478bd9Sstevel@tonic-gate 				if (dir_dev_acc(newpath, remainder_path,
477*7c478bd9Sstevel@tonic-gate 				    uid, gid, mode, line, errmsg)) {
478*7c478bd9Sstevel@tonic-gate 					err = -1;
479*7c478bd9Sstevel@tonic-gate 					break;
480*7c478bd9Sstevel@tonic-gate 				}
481*7c478bd9Sstevel@tonic-gate 			}
482*7c478bd9Sstevel@tonic-gate 		}
483*7c478bd9Sstevel@tonic-gate 		(void) closedir(dirp);
484*7c478bd9Sstevel@tonic-gate 		free(newpath);
485*7c478bd9Sstevel@tonic-gate 		free(match);
486*7c478bd9Sstevel@tonic-gate 		if (!alwaysmatch) {
487*7c478bd9Sstevel@tonic-gate 			regfree(&regex);
488*7c478bd9Sstevel@tonic-gate 		}
489*7c478bd9Sstevel@tonic-gate 	}
490*7c478bd9Sstevel@tonic-gate 
491*7c478bd9Sstevel@tonic-gate 	return (err);
492*7c478bd9Sstevel@tonic-gate }
493*7c478bd9Sstevel@tonic-gate 
494*7c478bd9Sstevel@tonic-gate /*
495*7c478bd9Sstevel@tonic-gate  * di_devperm_login - modify access of devices in /etc/logindevperm
496*7c478bd9Sstevel@tonic-gate  * by changing owner/group/permissions to that of ttyn.
497*7c478bd9Sstevel@tonic-gate  */
498*7c478bd9Sstevel@tonic-gate int
499*7c478bd9Sstevel@tonic-gate di_devperm_login(const char *ttyn, uid_t uid, gid_t gid,
500*7c478bd9Sstevel@tonic-gate     void (*errmsg)(char *))
501*7c478bd9Sstevel@tonic-gate {
502*7c478bd9Sstevel@tonic-gate 	int err;
503*7c478bd9Sstevel@tonic-gate 	struct group grp, *grpp;
504*7c478bd9Sstevel@tonic-gate 	gid_t tty_gid;
505*7c478bd9Sstevel@tonic-gate 	char grbuf[NSS_BUFLEN_GROUP];
506*7c478bd9Sstevel@tonic-gate 
507*7c478bd9Sstevel@tonic-gate 	if (errmsg == NULL)
508*7c478bd9Sstevel@tonic-gate 		errmsg = logerror;
509*7c478bd9Sstevel@tonic-gate 
510*7c478bd9Sstevel@tonic-gate 	if (ttyn == NULL) {
511*7c478bd9Sstevel@tonic-gate 		(*errmsg)("di_devperm_login: NULL tty device\n");
512*7c478bd9Sstevel@tonic-gate 		return (-1);
513*7c478bd9Sstevel@tonic-gate 	}
514*7c478bd9Sstevel@tonic-gate 
515*7c478bd9Sstevel@tonic-gate 	if (getgrnam_r("tty", &grp, grbuf, NSS_BUFLEN_GROUP, &grpp) != 0) {
516*7c478bd9Sstevel@tonic-gate 		tty_gid = grpp->gr_gid;
517*7c478bd9Sstevel@tonic-gate 	} else {
518*7c478bd9Sstevel@tonic-gate 		/*
519*7c478bd9Sstevel@tonic-gate 		 * this should never happen, but if it does set
520*7c478bd9Sstevel@tonic-gate 		 * group to tty's traditional value.
521*7c478bd9Sstevel@tonic-gate 		 */
522*7c478bd9Sstevel@tonic-gate 		tty_gid = 7;
523*7c478bd9Sstevel@tonic-gate 	}
524*7c478bd9Sstevel@tonic-gate 
525*7c478bd9Sstevel@tonic-gate 	/* set the login console device permission */
526*7c478bd9Sstevel@tonic-gate 	err = setdevaccess((char *)ttyn, uid, tty_gid,
527*7c478bd9Sstevel@tonic-gate 	    S_IRUSR|S_IWUSR|S_IWGRP, errmsg);
528*7c478bd9Sstevel@tonic-gate 	if (err) {
529*7c478bd9Sstevel@tonic-gate 		return (err);
530*7c478bd9Sstevel@tonic-gate 	}
531*7c478bd9Sstevel@tonic-gate 
532*7c478bd9Sstevel@tonic-gate 	/* set the device permissions */
533*7c478bd9Sstevel@tonic-gate 	return (logindevperm(ttyn, uid, gid, errmsg));
534*7c478bd9Sstevel@tonic-gate }
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate /*
537*7c478bd9Sstevel@tonic-gate  * di_devperm_logout - clean up access of devices in /etc/logindevperm
538*7c478bd9Sstevel@tonic-gate  * by resetting owner/group/permissions.
539*7c478bd9Sstevel@tonic-gate  */
540*7c478bd9Sstevel@tonic-gate int
541*7c478bd9Sstevel@tonic-gate di_devperm_logout(const char *ttyn)
542*7c478bd9Sstevel@tonic-gate {
543*7c478bd9Sstevel@tonic-gate 	struct passwd *pwd;
544*7c478bd9Sstevel@tonic-gate 	uid_t root_uid;
545*7c478bd9Sstevel@tonic-gate 	gid_t root_gid;
546*7c478bd9Sstevel@tonic-gate 
547*7c478bd9Sstevel@tonic-gate 	if (ttyn == NULL)
548*7c478bd9Sstevel@tonic-gate 		return (-1);
549*7c478bd9Sstevel@tonic-gate 
550*7c478bd9Sstevel@tonic-gate 	pwd = getpwnam("root");
551*7c478bd9Sstevel@tonic-gate 	if (pwd != NULL) {
552*7c478bd9Sstevel@tonic-gate 		root_uid = pwd->pw_uid;
553*7c478bd9Sstevel@tonic-gate 		root_gid = pwd->pw_gid;
554*7c478bd9Sstevel@tonic-gate 	} else {
555*7c478bd9Sstevel@tonic-gate 		/*
556*7c478bd9Sstevel@tonic-gate 		 * this should never happen, but if it does set user
557*7c478bd9Sstevel@tonic-gate 		 * and group to root's traditional values.
558*7c478bd9Sstevel@tonic-gate 		 */
559*7c478bd9Sstevel@tonic-gate 		root_uid = 0;
560*7c478bd9Sstevel@tonic-gate 		root_gid = 0;
561*7c478bd9Sstevel@tonic-gate 	}
562*7c478bd9Sstevel@tonic-gate 
563*7c478bd9Sstevel@tonic-gate 	return (logindevperm(ttyn, root_uid, root_gid, NULL));
564*7c478bd9Sstevel@tonic-gate }
565*7c478bd9Sstevel@tonic-gate 
566*7c478bd9Sstevel@tonic-gate static void
567*7c478bd9Sstevel@tonic-gate logerror(char *errstring)
568*7c478bd9Sstevel@tonic-gate {
569*7c478bd9Sstevel@tonic-gate 	syslog(LOG_AUTH | LOG_CRIT, "%s", errstring);
570*7c478bd9Sstevel@tonic-gate }
571*7c478bd9Sstevel@tonic-gate 
572*7c478bd9Sstevel@tonic-gate 
573*7c478bd9Sstevel@tonic-gate /*
574*7c478bd9Sstevel@tonic-gate  * Tokens are separated by ' ', '\t', ':', '=', '&', '|', ';', '\n', or '\0'
575*7c478bd9Sstevel@tonic-gate  */
576*7c478bd9Sstevel@tonic-gate static int
577*7c478bd9Sstevel@tonic-gate getnexttoken(char *next, char **nextp, char **tokenpp, char *tchar)
578*7c478bd9Sstevel@tonic-gate {
579*7c478bd9Sstevel@tonic-gate 	char *cp;
580*7c478bd9Sstevel@tonic-gate 	char *cp1;
581*7c478bd9Sstevel@tonic-gate 	char *tokenp;
582*7c478bd9Sstevel@tonic-gate 
583*7c478bd9Sstevel@tonic-gate 	cp = next;
584*7c478bd9Sstevel@tonic-gate 	while (*cp == ' ' || *cp == '\t') {
585*7c478bd9Sstevel@tonic-gate 		cp++;			/* skip leading spaces */
586*7c478bd9Sstevel@tonic-gate 	}
587*7c478bd9Sstevel@tonic-gate 	tokenp = cp;			/* start of token */
588*7c478bd9Sstevel@tonic-gate 	while (*cp != '\0' && *cp != '\n' && *cp != ' ' && *cp != '\t' &&
589*7c478bd9Sstevel@tonic-gate 		*cp != ':' && *cp != '=' && *cp != '&' &&
590*7c478bd9Sstevel@tonic-gate 		*cp != '|' && *cp != ';') {
591*7c478bd9Sstevel@tonic-gate 		cp++;			/* point to next character */
592*7c478bd9Sstevel@tonic-gate 	}
593*7c478bd9Sstevel@tonic-gate 	/*
594*7c478bd9Sstevel@tonic-gate 	 * If terminating character is a space or tab, look ahead to see if
595*7c478bd9Sstevel@tonic-gate 	 * there's another terminator that's not a space or a tab.
596*7c478bd9Sstevel@tonic-gate 	 * (This code handles trailing spaces.)
597*7c478bd9Sstevel@tonic-gate 	 */
598*7c478bd9Sstevel@tonic-gate 	if (*cp == ' ' || *cp == '\t') {
599*7c478bd9Sstevel@tonic-gate 		cp1 = cp;
600*7c478bd9Sstevel@tonic-gate 		while (*++cp1 == ' ' || *cp1 == '\t')
601*7c478bd9Sstevel@tonic-gate 			;
602*7c478bd9Sstevel@tonic-gate 		if (*cp1 == '=' || *cp1 == ':' || *cp1 == '&' || *cp1 == '|' ||
603*7c478bd9Sstevel@tonic-gate 			*cp1 == ';' || *cp1 == '\n' || *cp1 == '\0') {
604*7c478bd9Sstevel@tonic-gate 			*cp = NULL;	/* terminate token */
605*7c478bd9Sstevel@tonic-gate 			cp = cp1;
606*7c478bd9Sstevel@tonic-gate 		}
607*7c478bd9Sstevel@tonic-gate 	}
608*7c478bd9Sstevel@tonic-gate 	if (tchar != NULL) {
609*7c478bd9Sstevel@tonic-gate 		*tchar = *cp;		/* save terminating character */
610*7c478bd9Sstevel@tonic-gate 		if (*tchar == '\0') {
611*7c478bd9Sstevel@tonic-gate 			*tchar = '\n';
612*7c478bd9Sstevel@tonic-gate 		}
613*7c478bd9Sstevel@tonic-gate 	}
614*7c478bd9Sstevel@tonic-gate 	*cp++ = '\0';			/* terminate token, point to next */
615*7c478bd9Sstevel@tonic-gate 	*nextp = cp;			/* set pointer to next character */
616*7c478bd9Sstevel@tonic-gate 	if (cp - tokenp - 1 == 0) {
617*7c478bd9Sstevel@tonic-gate 		return (0);
618*7c478bd9Sstevel@tonic-gate 	}
619*7c478bd9Sstevel@tonic-gate 	*tokenpp = tokenp;
620*7c478bd9Sstevel@tonic-gate 	return (1);
621*7c478bd9Sstevel@tonic-gate }
622*7c478bd9Sstevel@tonic-gate 
623*7c478bd9Sstevel@tonic-gate /*
624*7c478bd9Sstevel@tonic-gate  * get a decimal octal or hex number. Handle '~' for one's complement.
625*7c478bd9Sstevel@tonic-gate  */
626*7c478bd9Sstevel@tonic-gate static int
627*7c478bd9Sstevel@tonic-gate getvalue(char *token, int *valuep)
628*7c478bd9Sstevel@tonic-gate {
629*7c478bd9Sstevel@tonic-gate 	int radix;
630*7c478bd9Sstevel@tonic-gate 	int retval = 0;
631*7c478bd9Sstevel@tonic-gate 	int onescompl = 0;
632*7c478bd9Sstevel@tonic-gate 	int negate = 0;
633*7c478bd9Sstevel@tonic-gate 	char c;
634*7c478bd9Sstevel@tonic-gate 
635*7c478bd9Sstevel@tonic-gate 	if (*token == '~') {
636*7c478bd9Sstevel@tonic-gate 		onescompl++; /* perform one's complement on result */
637*7c478bd9Sstevel@tonic-gate 		token++;
638*7c478bd9Sstevel@tonic-gate 	} else if (*token == '-') {
639*7c478bd9Sstevel@tonic-gate 		negate++;
640*7c478bd9Sstevel@tonic-gate 		token++;
641*7c478bd9Sstevel@tonic-gate 	}
642*7c478bd9Sstevel@tonic-gate 	if (*token == '0') {
643*7c478bd9Sstevel@tonic-gate 		token++;
644*7c478bd9Sstevel@tonic-gate 		c = *token;
645*7c478bd9Sstevel@tonic-gate 
646*7c478bd9Sstevel@tonic-gate 		if (c == '\0') {
647*7c478bd9Sstevel@tonic-gate 			*valuep = 0;	/* value is 0 */
648*7c478bd9Sstevel@tonic-gate 			return (0);
649*7c478bd9Sstevel@tonic-gate 		}
650*7c478bd9Sstevel@tonic-gate 
651*7c478bd9Sstevel@tonic-gate 		if (c == 'x' || c == 'X') {
652*7c478bd9Sstevel@tonic-gate 			radix = 16;
653*7c478bd9Sstevel@tonic-gate 			token++;
654*7c478bd9Sstevel@tonic-gate 		} else {
655*7c478bd9Sstevel@tonic-gate 			radix = 8;
656*7c478bd9Sstevel@tonic-gate 		}
657*7c478bd9Sstevel@tonic-gate 	} else
658*7c478bd9Sstevel@tonic-gate 		radix = 10;
659*7c478bd9Sstevel@tonic-gate 
660*7c478bd9Sstevel@tonic-gate 	while ((c = *token++)) {
661*7c478bd9Sstevel@tonic-gate 		switch (radix) {
662*7c478bd9Sstevel@tonic-gate 		case 8:
663*7c478bd9Sstevel@tonic-gate 			if (c >= '0' && c <= '7') {
664*7c478bd9Sstevel@tonic-gate 				c -= '0';
665*7c478bd9Sstevel@tonic-gate 			} else {
666*7c478bd9Sstevel@tonic-gate 				/* invalid number */
667*7c478bd9Sstevel@tonic-gate 				return (0);
668*7c478bd9Sstevel@tonic-gate 			}
669*7c478bd9Sstevel@tonic-gate 			retval = (retval << 3) + c;
670*7c478bd9Sstevel@tonic-gate 			break;
671*7c478bd9Sstevel@tonic-gate 		case 10:
672*7c478bd9Sstevel@tonic-gate 			if (c >= '0' && c <= '9') {
673*7c478bd9Sstevel@tonic-gate 				c -= '0';
674*7c478bd9Sstevel@tonic-gate 			} else {
675*7c478bd9Sstevel@tonic-gate 				/* invalid number */
676*7c478bd9Sstevel@tonic-gate 				return (0);
677*7c478bd9Sstevel@tonic-gate 			}
678*7c478bd9Sstevel@tonic-gate 			retval = (retval * 10) + c;
679*7c478bd9Sstevel@tonic-gate 			break;
680*7c478bd9Sstevel@tonic-gate 		case 16:
681*7c478bd9Sstevel@tonic-gate 			if (c >= 'a' && c <= 'f') {
682*7c478bd9Sstevel@tonic-gate 				c = c - 'a' + 10;
683*7c478bd9Sstevel@tonic-gate 			} else if (c >= 'A' && c <= 'F') {
684*7c478bd9Sstevel@tonic-gate 				c = c - 'A' + 10;
685*7c478bd9Sstevel@tonic-gate 			} else if (c >= '0' && c <= '9') {
686*7c478bd9Sstevel@tonic-gate 				c -= '0';
687*7c478bd9Sstevel@tonic-gate 			} else {
688*7c478bd9Sstevel@tonic-gate 				/* invalid number */
689*7c478bd9Sstevel@tonic-gate 				return (0);
690*7c478bd9Sstevel@tonic-gate 			}
691*7c478bd9Sstevel@tonic-gate 			retval = (retval << 4) + c;
692*7c478bd9Sstevel@tonic-gate 			break;
693*7c478bd9Sstevel@tonic-gate 		}
694*7c478bd9Sstevel@tonic-gate 	}
695*7c478bd9Sstevel@tonic-gate 	if (onescompl) {
696*7c478bd9Sstevel@tonic-gate 		retval = ~retval;
697*7c478bd9Sstevel@tonic-gate 	}
698*7c478bd9Sstevel@tonic-gate 	if (negate) {
699*7c478bd9Sstevel@tonic-gate 		retval = -retval;
700*7c478bd9Sstevel@tonic-gate 	}
701*7c478bd9Sstevel@tonic-gate 	*valuep = retval;
702*7c478bd9Sstevel@tonic-gate 	return (1);
703*7c478bd9Sstevel@tonic-gate }
704*7c478bd9Sstevel@tonic-gate 
705*7c478bd9Sstevel@tonic-gate /*
706*7c478bd9Sstevel@tonic-gate  * Read /etc/minor_perm, return mperm list of entries
707*7c478bd9Sstevel@tonic-gate  */
708*7c478bd9Sstevel@tonic-gate struct mperm *
709*7c478bd9Sstevel@tonic-gate i_devfs_read_minor_perm(char *drvname, void (*errcb)(minorperm_err_t, int))
710*7c478bd9Sstevel@tonic-gate {
711*7c478bd9Sstevel@tonic-gate 	FILE *pfd;
712*7c478bd9Sstevel@tonic-gate 	struct mperm *mp;
713*7c478bd9Sstevel@tonic-gate 	char line[MAX_MINOR_PERM_LINE];
714*7c478bd9Sstevel@tonic-gate 	char *cp, *p, t;
715*7c478bd9Sstevel@tonic-gate 	struct mperm *minor_perms = NULL;
716*7c478bd9Sstevel@tonic-gate 	struct mperm *mptail = NULL;
717*7c478bd9Sstevel@tonic-gate 	struct passwd *pw;
718*7c478bd9Sstevel@tonic-gate 	struct group *gp;
719*7c478bd9Sstevel@tonic-gate 	uid_t root_uid;
720*7c478bd9Sstevel@tonic-gate 	gid_t sys_gid;
721*7c478bd9Sstevel@tonic-gate 	int ln = 0;
722*7c478bd9Sstevel@tonic-gate 
723*7c478bd9Sstevel@tonic-gate 	/*
724*7c478bd9Sstevel@tonic-gate 	 * Get root/sys ids, these being the most common
725*7c478bd9Sstevel@tonic-gate 	 */
726*7c478bd9Sstevel@tonic-gate 	if ((pw = getpwnam(DEFAULT_DEV_USER)) != NULL) {
727*7c478bd9Sstevel@tonic-gate 		root_uid = pw->pw_uid;
728*7c478bd9Sstevel@tonic-gate 	} else {
729*7c478bd9Sstevel@tonic-gate 		(*errcb)(MP_CANT_FIND_USER_ERR, 0);
730*7c478bd9Sstevel@tonic-gate 		root_uid = (uid_t)0;	/* assume 0 is root */
731*7c478bd9Sstevel@tonic-gate 	}
732*7c478bd9Sstevel@tonic-gate 	if ((gp = getgrnam(DEFAULT_DEV_GROUP)) != NULL) {
733*7c478bd9Sstevel@tonic-gate 		sys_gid = gp->gr_gid;
734*7c478bd9Sstevel@tonic-gate 	} else {
735*7c478bd9Sstevel@tonic-gate 		(*errcb)(MP_CANT_FIND_GROUP_ERR, 0);
736*7c478bd9Sstevel@tonic-gate 		sys_gid = (gid_t)3;	/* assume 3 is sys */
737*7c478bd9Sstevel@tonic-gate 	}
738*7c478bd9Sstevel@tonic-gate 
739*7c478bd9Sstevel@tonic-gate 	if ((pfd = fopen(MINOR_PERM_FILE, "r")) == NULL) {
740*7c478bd9Sstevel@tonic-gate 		(*errcb)(MP_FOPEN_ERR, errno);
741*7c478bd9Sstevel@tonic-gate 		return (NULL);
742*7c478bd9Sstevel@tonic-gate 	}
743*7c478bd9Sstevel@tonic-gate 	while (fgets(line, MAX_MINOR_PERM_LINE - 1, pfd) != NULL) {
744*7c478bd9Sstevel@tonic-gate 		ln++;
745*7c478bd9Sstevel@tonic-gate 		mp = (struct mperm *)calloc(1, sizeof (struct mperm));
746*7c478bd9Sstevel@tonic-gate 		if (mp == NULL) {
747*7c478bd9Sstevel@tonic-gate 			(*errcb)(MP_ALLOC_ERR, sizeof (struct mperm));
748*7c478bd9Sstevel@tonic-gate 			continue;
749*7c478bd9Sstevel@tonic-gate 		}
750*7c478bd9Sstevel@tonic-gate 		cp = line;
751*7c478bd9Sstevel@tonic-gate 		if (getnexttoken(cp, &cp, &p, &t) == 0) {
752*7c478bd9Sstevel@tonic-gate 			(*errcb)(MP_IGNORING_LINE_ERR, ln);
753*7c478bd9Sstevel@tonic-gate 			devfs_free_minor_perm(mp);
754*7c478bd9Sstevel@tonic-gate 			continue;
755*7c478bd9Sstevel@tonic-gate 		}
756*7c478bd9Sstevel@tonic-gate 		mp->mp_drvname = strdup(p);
757*7c478bd9Sstevel@tonic-gate 		if (mp->mp_drvname == NULL) {
758*7c478bd9Sstevel@tonic-gate 			(*errcb)(MP_ALLOC_ERR, strlen(p)+1);
759*7c478bd9Sstevel@tonic-gate 			devfs_free_minor_perm(mp);
760*7c478bd9Sstevel@tonic-gate 			continue;
761*7c478bd9Sstevel@tonic-gate 		} else if (t == '\n' || t == '\0') {
762*7c478bd9Sstevel@tonic-gate 			(*errcb)(MP_IGNORING_LINE_ERR, ln);
763*7c478bd9Sstevel@tonic-gate 			devfs_free_minor_perm(mp);
764*7c478bd9Sstevel@tonic-gate 			continue;
765*7c478bd9Sstevel@tonic-gate 		}
766*7c478bd9Sstevel@tonic-gate 		if (t == ':') {
767*7c478bd9Sstevel@tonic-gate 			if (getnexttoken(cp, &cp, &p, &t) == 0) {
768*7c478bd9Sstevel@tonic-gate 				(*errcb)(MP_IGNORING_LINE_ERR, ln);
769*7c478bd9Sstevel@tonic-gate 				devfs_free_minor_perm(mp);
770*7c478bd9Sstevel@tonic-gate 			}
771*7c478bd9Sstevel@tonic-gate 			mp->mp_minorname = strdup(p);
772*7c478bd9Sstevel@tonic-gate 			if (mp->mp_minorname == NULL) {
773*7c478bd9Sstevel@tonic-gate 				(*errcb)(MP_ALLOC_ERR, strlen(p)+1);
774*7c478bd9Sstevel@tonic-gate 				devfs_free_minor_perm(mp);
775*7c478bd9Sstevel@tonic-gate 				continue;
776*7c478bd9Sstevel@tonic-gate 			}
777*7c478bd9Sstevel@tonic-gate 		} else {
778*7c478bd9Sstevel@tonic-gate 			mp->mp_minorname = NULL;
779*7c478bd9Sstevel@tonic-gate 		}
780*7c478bd9Sstevel@tonic-gate 
781*7c478bd9Sstevel@tonic-gate 		if (t == '\n' || t == '\0') {
782*7c478bd9Sstevel@tonic-gate 			devfs_free_minor_perm(mp);
783*7c478bd9Sstevel@tonic-gate 			(*errcb)(MP_IGNORING_LINE_ERR, ln);
784*7c478bd9Sstevel@tonic-gate 			continue;
785*7c478bd9Sstevel@tonic-gate 		}
786*7c478bd9Sstevel@tonic-gate 		if (getnexttoken(cp, &cp, &p, &t) == 0) {
787*7c478bd9Sstevel@tonic-gate 			goto link;
788*7c478bd9Sstevel@tonic-gate 		}
789*7c478bd9Sstevel@tonic-gate 		if (getvalue(p, (int *)&mp->mp_mode) == 0) {
790*7c478bd9Sstevel@tonic-gate 			goto link;
791*7c478bd9Sstevel@tonic-gate 		}
792*7c478bd9Sstevel@tonic-gate 		if (t == '\n' || t == '\0') {	/* no owner or group */
793*7c478bd9Sstevel@tonic-gate 			goto link;
794*7c478bd9Sstevel@tonic-gate 		}
795*7c478bd9Sstevel@tonic-gate 		if (getnexttoken(cp, &cp, &p, &t) == 0) {
796*7c478bd9Sstevel@tonic-gate 			goto link;
797*7c478bd9Sstevel@tonic-gate 		}
798*7c478bd9Sstevel@tonic-gate 		mp->mp_owner = strdup(p);
799*7c478bd9Sstevel@tonic-gate 		if (mp->mp_owner == NULL) {
800*7c478bd9Sstevel@tonic-gate 			(*errcb)(MP_ALLOC_ERR, strlen(p)+1);
801*7c478bd9Sstevel@tonic-gate 			devfs_free_minor_perm(mp);
802*7c478bd9Sstevel@tonic-gate 			continue;
803*7c478bd9Sstevel@tonic-gate 		} else if (t == '\n' || t == '\0') {	/* no group */
804*7c478bd9Sstevel@tonic-gate 			goto link;
805*7c478bd9Sstevel@tonic-gate 		}
806*7c478bd9Sstevel@tonic-gate 		if (getnexttoken(cp, &cp, &p, 0) == 0) {
807*7c478bd9Sstevel@tonic-gate 			goto link;
808*7c478bd9Sstevel@tonic-gate 		}
809*7c478bd9Sstevel@tonic-gate 		mp->mp_group = strdup(p);
810*7c478bd9Sstevel@tonic-gate 		if (mp->mp_group == NULL) {
811*7c478bd9Sstevel@tonic-gate 			(*errcb)(MP_ALLOC_ERR, strlen(p)+1);
812*7c478bd9Sstevel@tonic-gate 			devfs_free_minor_perm(mp);
813*7c478bd9Sstevel@tonic-gate 			continue;
814*7c478bd9Sstevel@tonic-gate 		}
815*7c478bd9Sstevel@tonic-gate link:
816*7c478bd9Sstevel@tonic-gate 		if (drvname != NULL) {
817*7c478bd9Sstevel@tonic-gate 			/*
818*7c478bd9Sstevel@tonic-gate 			 * We only want the minor perm entry for a
819*7c478bd9Sstevel@tonic-gate 			 * the named driver.  The driver name is the
820*7c478bd9Sstevel@tonic-gate 			 * minor in the clone case.
821*7c478bd9Sstevel@tonic-gate 			 */
822*7c478bd9Sstevel@tonic-gate 			if (strcmp(mp->mp_drvname, "clone") == 0) {
823*7c478bd9Sstevel@tonic-gate 				if (mp->mp_minorname == NULL ||
824*7c478bd9Sstevel@tonic-gate 				    strcmp(drvname, mp->mp_minorname) != 0) {
825*7c478bd9Sstevel@tonic-gate 					devfs_free_minor_perm(mp);
826*7c478bd9Sstevel@tonic-gate 					continue;
827*7c478bd9Sstevel@tonic-gate 				}
828*7c478bd9Sstevel@tonic-gate 			} else {
829*7c478bd9Sstevel@tonic-gate 				if (strcmp(drvname, mp->mp_drvname) != 0) {
830*7c478bd9Sstevel@tonic-gate 					devfs_free_minor_perm(mp);
831*7c478bd9Sstevel@tonic-gate 					continue;
832*7c478bd9Sstevel@tonic-gate 				}
833*7c478bd9Sstevel@tonic-gate 			}
834*7c478bd9Sstevel@tonic-gate 		}
835*7c478bd9Sstevel@tonic-gate 		if (minor_perms == NULL) {
836*7c478bd9Sstevel@tonic-gate 			minor_perms = mp;
837*7c478bd9Sstevel@tonic-gate 		} else {
838*7c478bd9Sstevel@tonic-gate 			mptail->mp_next = mp;
839*7c478bd9Sstevel@tonic-gate 		}
840*7c478bd9Sstevel@tonic-gate 		mptail = mp;
841*7c478bd9Sstevel@tonic-gate 
842*7c478bd9Sstevel@tonic-gate 		/*
843*7c478bd9Sstevel@tonic-gate 		 * Compute the uid's and gid's here - there are
844*7c478bd9Sstevel@tonic-gate 		 * fewer lines in the /etc/minor_perm file than there
845*7c478bd9Sstevel@tonic-gate 		 * are devices to be stat(2)ed.  And almost every
846*7c478bd9Sstevel@tonic-gate 		 * device is 'root sys'.  See 1135520.
847*7c478bd9Sstevel@tonic-gate 		 */
848*7c478bd9Sstevel@tonic-gate 		if (mp->mp_owner == NULL ||
849*7c478bd9Sstevel@tonic-gate 		    strcmp(mp->mp_owner, DEFAULT_DEV_USER) == 0 ||
850*7c478bd9Sstevel@tonic-gate 		    (pw = getpwnam(mp->mp_owner)) == NULL) {
851*7c478bd9Sstevel@tonic-gate 			mp->mp_uid = root_uid;
852*7c478bd9Sstevel@tonic-gate 		} else {
853*7c478bd9Sstevel@tonic-gate 			mp->mp_uid = pw->pw_uid;
854*7c478bd9Sstevel@tonic-gate 		}
855*7c478bd9Sstevel@tonic-gate 
856*7c478bd9Sstevel@tonic-gate 		if (mp->mp_group == NULL ||
857*7c478bd9Sstevel@tonic-gate 		    strcmp(mp->mp_group, DEFAULT_DEV_GROUP) == 0 ||
858*7c478bd9Sstevel@tonic-gate 		    (gp = getgrnam(mp->mp_group)) == NULL) {
859*7c478bd9Sstevel@tonic-gate 			mp->mp_gid = sys_gid;
860*7c478bd9Sstevel@tonic-gate 		} else {
861*7c478bd9Sstevel@tonic-gate 			mp->mp_gid = gp->gr_gid;
862*7c478bd9Sstevel@tonic-gate 		}
863*7c478bd9Sstevel@tonic-gate 	}
864*7c478bd9Sstevel@tonic-gate 
865*7c478bd9Sstevel@tonic-gate 	if (fclose(pfd) == EOF) {
866*7c478bd9Sstevel@tonic-gate 		(*errcb)(MP_FCLOSE_ERR, errno);
867*7c478bd9Sstevel@tonic-gate 	}
868*7c478bd9Sstevel@tonic-gate 
869*7c478bd9Sstevel@tonic-gate 	return (minor_perms);
870*7c478bd9Sstevel@tonic-gate }
871*7c478bd9Sstevel@tonic-gate 
872*7c478bd9Sstevel@tonic-gate struct mperm *
873*7c478bd9Sstevel@tonic-gate devfs_read_minor_perm(void (*errcb)(minorperm_err_t, int))
874*7c478bd9Sstevel@tonic-gate {
875*7c478bd9Sstevel@tonic-gate 	return (i_devfs_read_minor_perm(NULL, errcb));
876*7c478bd9Sstevel@tonic-gate }
877*7c478bd9Sstevel@tonic-gate 
878*7c478bd9Sstevel@tonic-gate static struct mperm *
879*7c478bd9Sstevel@tonic-gate i_devfs_read_minor_perm_by_driver(char *drvname,
880*7c478bd9Sstevel@tonic-gate 	void (*errcb)(minorperm_err_t mp_err, int key))
881*7c478bd9Sstevel@tonic-gate {
882*7c478bd9Sstevel@tonic-gate 	return (i_devfs_read_minor_perm(drvname, errcb));
883*7c478bd9Sstevel@tonic-gate }
884*7c478bd9Sstevel@tonic-gate 
885*7c478bd9Sstevel@tonic-gate /*
886*7c478bd9Sstevel@tonic-gate  * Free mperm list of entries
887*7c478bd9Sstevel@tonic-gate  */
888*7c478bd9Sstevel@tonic-gate void
889*7c478bd9Sstevel@tonic-gate devfs_free_minor_perm(struct mperm *mplist)
890*7c478bd9Sstevel@tonic-gate {
891*7c478bd9Sstevel@tonic-gate 	struct mperm *mp, *next;
892*7c478bd9Sstevel@tonic-gate 
893*7c478bd9Sstevel@tonic-gate 	for (mp = mplist; mp != NULL; mp = next) {
894*7c478bd9Sstevel@tonic-gate 		next = mp->mp_next;
895*7c478bd9Sstevel@tonic-gate 
896*7c478bd9Sstevel@tonic-gate 		if (mp->mp_drvname)
897*7c478bd9Sstevel@tonic-gate 			free(mp->mp_drvname);
898*7c478bd9Sstevel@tonic-gate 		if (mp->mp_minorname)
899*7c478bd9Sstevel@tonic-gate 			free(mp->mp_minorname);
900*7c478bd9Sstevel@tonic-gate 		if (mp->mp_owner)
901*7c478bd9Sstevel@tonic-gate 			free(mp->mp_owner);
902*7c478bd9Sstevel@tonic-gate 		if (mp->mp_group)
903*7c478bd9Sstevel@tonic-gate 			free(mp->mp_group);
904*7c478bd9Sstevel@tonic-gate 		free(mp);
905*7c478bd9Sstevel@tonic-gate 	}
906*7c478bd9Sstevel@tonic-gate }
907*7c478bd9Sstevel@tonic-gate 
908*7c478bd9Sstevel@tonic-gate static int
909*7c478bd9Sstevel@tonic-gate i_devfs_add_perm_entry(nvlist_t *nvl, struct mperm *mp)
910*7c478bd9Sstevel@tonic-gate {
911*7c478bd9Sstevel@tonic-gate 	int err;
912*7c478bd9Sstevel@tonic-gate 
913*7c478bd9Sstevel@tonic-gate 	err = nvlist_add_string(nvl, mp->mp_drvname, mp->mp_minorname);
914*7c478bd9Sstevel@tonic-gate 	if (err != 0)
915*7c478bd9Sstevel@tonic-gate 		return (err);
916*7c478bd9Sstevel@tonic-gate 
917*7c478bd9Sstevel@tonic-gate 	err = nvlist_add_int32(nvl, "mode", (int32_t)mp->mp_mode);
918*7c478bd9Sstevel@tonic-gate 	if (err != 0)
919*7c478bd9Sstevel@tonic-gate 		return (err);
920*7c478bd9Sstevel@tonic-gate 
921*7c478bd9Sstevel@tonic-gate 	err = nvlist_add_int32(nvl, "uid", (int32_t)mp->mp_uid);
922*7c478bd9Sstevel@tonic-gate 	if (err != 0)
923*7c478bd9Sstevel@tonic-gate 		return (err);
924*7c478bd9Sstevel@tonic-gate 
925*7c478bd9Sstevel@tonic-gate 	err = nvlist_add_int32(nvl, "gid", (int32_t)mp->mp_gid);
926*7c478bd9Sstevel@tonic-gate 	return (err);
927*7c478bd9Sstevel@tonic-gate }
928*7c478bd9Sstevel@tonic-gate 
929*7c478bd9Sstevel@tonic-gate static nvlist_t *
930*7c478bd9Sstevel@tonic-gate i_devfs_minor_perm_nvlist(struct mperm *mplist,
931*7c478bd9Sstevel@tonic-gate 	void (*errcb)(minorperm_err_t, int))
932*7c478bd9Sstevel@tonic-gate {
933*7c478bd9Sstevel@tonic-gate 	int err;
934*7c478bd9Sstevel@tonic-gate 	struct mperm *mp;
935*7c478bd9Sstevel@tonic-gate 	nvlist_t *nvl = NULL;
936*7c478bd9Sstevel@tonic-gate 
937*7c478bd9Sstevel@tonic-gate 	if ((err = nvlist_alloc(&nvl, 0, 0)) != 0) {
938*7c478bd9Sstevel@tonic-gate 		(*errcb)(MP_NVLIST_ERR, err);
939*7c478bd9Sstevel@tonic-gate 		return (NULL);
940*7c478bd9Sstevel@tonic-gate 	}
941*7c478bd9Sstevel@tonic-gate 
942*7c478bd9Sstevel@tonic-gate 	for (mp = mplist; mp != NULL; mp = mp->mp_next) {
943*7c478bd9Sstevel@tonic-gate 		if ((err = i_devfs_add_perm_entry(nvl, mp)) != 0) {
944*7c478bd9Sstevel@tonic-gate 			(*errcb)(MP_NVLIST_ERR, err);
945*7c478bd9Sstevel@tonic-gate 			nvlist_free(nvl);
946*7c478bd9Sstevel@tonic-gate 			return (NULL);
947*7c478bd9Sstevel@tonic-gate 		}
948*7c478bd9Sstevel@tonic-gate 	}
949*7c478bd9Sstevel@tonic-gate 
950*7c478bd9Sstevel@tonic-gate 	return (nvl);
951*7c478bd9Sstevel@tonic-gate }
952*7c478bd9Sstevel@tonic-gate 
953*7c478bd9Sstevel@tonic-gate /*
954*7c478bd9Sstevel@tonic-gate  * Load all minor perm entries into the kernel
955*7c478bd9Sstevel@tonic-gate  * Done at boot time via devfsadm
956*7c478bd9Sstevel@tonic-gate  */
957*7c478bd9Sstevel@tonic-gate int
958*7c478bd9Sstevel@tonic-gate devfs_load_minor_perm(struct mperm *mplist,
959*7c478bd9Sstevel@tonic-gate 	void (*errcb)(minorperm_err_t, int))
960*7c478bd9Sstevel@tonic-gate {
961*7c478bd9Sstevel@tonic-gate 	int err;
962*7c478bd9Sstevel@tonic-gate 	char *buf = NULL;
963*7c478bd9Sstevel@tonic-gate 	size_t buflen;
964*7c478bd9Sstevel@tonic-gate 	nvlist_t *nvl;
965*7c478bd9Sstevel@tonic-gate 
966*7c478bd9Sstevel@tonic-gate 	nvl = i_devfs_minor_perm_nvlist(mplist, errcb);
967*7c478bd9Sstevel@tonic-gate 	if (nvl == NULL)
968*7c478bd9Sstevel@tonic-gate 		return (-1);
969*7c478bd9Sstevel@tonic-gate 
970*7c478bd9Sstevel@tonic-gate 	if (nvlist_pack(nvl, &buf, &buflen, NV_ENCODE_NATIVE, 0) != 0) {
971*7c478bd9Sstevel@tonic-gate 		nvlist_free(nvl);
972*7c478bd9Sstevel@tonic-gate 		return (-1);
973*7c478bd9Sstevel@tonic-gate 	}
974*7c478bd9Sstevel@tonic-gate 
975*7c478bd9Sstevel@tonic-gate 	err = modctl(MODLOADMINORPERM, buf, buflen);
976*7c478bd9Sstevel@tonic-gate 	nvlist_free(nvl);
977*7c478bd9Sstevel@tonic-gate 	free(buf);
978*7c478bd9Sstevel@tonic-gate 
979*7c478bd9Sstevel@tonic-gate 	return (err);
980*7c478bd9Sstevel@tonic-gate }
981*7c478bd9Sstevel@tonic-gate 
982*7c478bd9Sstevel@tonic-gate /*
983*7c478bd9Sstevel@tonic-gate  * Add/remove minor perm entry for a driver
984*7c478bd9Sstevel@tonic-gate  */
985*7c478bd9Sstevel@tonic-gate static int
986*7c478bd9Sstevel@tonic-gate i_devfs_update_minor_perm(char *drv, int ctl,
987*7c478bd9Sstevel@tonic-gate 	void (*errcb)(minorperm_err_t, int))
988*7c478bd9Sstevel@tonic-gate {
989*7c478bd9Sstevel@tonic-gate 	int err;
990*7c478bd9Sstevel@tonic-gate 	char *buf;
991*7c478bd9Sstevel@tonic-gate 	size_t buflen;
992*7c478bd9Sstevel@tonic-gate 	nvlist_t *nvl;
993*7c478bd9Sstevel@tonic-gate 	struct mperm *mplist;
994*7c478bd9Sstevel@tonic-gate 
995*7c478bd9Sstevel@tonic-gate 	mplist = i_devfs_read_minor_perm_by_driver(drv, errcb);
996*7c478bd9Sstevel@tonic-gate 
997*7c478bd9Sstevel@tonic-gate 	nvl = i_devfs_minor_perm_nvlist(mplist, errcb);
998*7c478bd9Sstevel@tonic-gate 	if (nvl == NULL)
999*7c478bd9Sstevel@tonic-gate 		return (-1);
1000*7c478bd9Sstevel@tonic-gate 
1001*7c478bd9Sstevel@tonic-gate 	buf = NULL;
1002*7c478bd9Sstevel@tonic-gate 	if (nvlist_pack(nvl, &buf, &buflen, NV_ENCODE_NATIVE, 0) != 0) {
1003*7c478bd9Sstevel@tonic-gate 		nvlist_free(nvl);
1004*7c478bd9Sstevel@tonic-gate 		return (-1);
1005*7c478bd9Sstevel@tonic-gate 	}
1006*7c478bd9Sstevel@tonic-gate 
1007*7c478bd9Sstevel@tonic-gate 	err = modctl(ctl, buf, buflen);
1008*7c478bd9Sstevel@tonic-gate 	nvlist_free(nvl);
1009*7c478bd9Sstevel@tonic-gate 	devfs_free_minor_perm(mplist);
1010*7c478bd9Sstevel@tonic-gate 	free(buf);
1011*7c478bd9Sstevel@tonic-gate 
1012*7c478bd9Sstevel@tonic-gate 	return (err);
1013*7c478bd9Sstevel@tonic-gate }
1014*7c478bd9Sstevel@tonic-gate 
1015*7c478bd9Sstevel@tonic-gate int
1016*7c478bd9Sstevel@tonic-gate devfs_add_minor_perm(char *drv,
1017*7c478bd9Sstevel@tonic-gate 	void (*errcb)(minorperm_err_t, int))
1018*7c478bd9Sstevel@tonic-gate {
1019*7c478bd9Sstevel@tonic-gate 	return (i_devfs_update_minor_perm(drv, MODADDMINORPERM, errcb));
1020*7c478bd9Sstevel@tonic-gate }
1021*7c478bd9Sstevel@tonic-gate 
1022*7c478bd9Sstevel@tonic-gate int
1023*7c478bd9Sstevel@tonic-gate devfs_rm_minor_perm(char *drv,
1024*7c478bd9Sstevel@tonic-gate 	void (*errcb)(minorperm_err_t, int))
1025*7c478bd9Sstevel@tonic-gate {
1026*7c478bd9Sstevel@tonic-gate 	return (i_devfs_update_minor_perm(drv, MODREMMINORPERM, errcb));
1027*7c478bd9Sstevel@tonic-gate }
1028