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
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.
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]
23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
26 * Device policy specific subroutines. We cannot merge them with
27 * drvsubr.c because of static linking requirements.
30 #pragma ident "%Z%%M% %I% %E% SMI"
43 #include <sys/modctl.h>
44 #include <sys/devpolicy.h>
46 #include <sys/sysmacros.h>
53 const priv_impl_info_t
*privimplinfo
;
56 * New token types should be parsed in parse_plcy_entry.
60 typedef struct token
{
66 static token_t toktab
[] = {
67 { DEVPLCY_TKN_RDP
, PSET
/* offsetof(devplcysys_t, dps_rdp) */ },
68 { DEVPLCY_TKN_WRP
, PSET
/* offsetof(devplcysys_t, dps_wrp) */ },
74 #define NTOK (sizeof (toktab)/sizeof (token_t))
77 * Compute the size of the datastructures needed.
82 if ((privimplinfo
= getprivimplinfo()) == NULL
) {
83 (void) fprintf(stderr
, gettext(ERR_PRIVIMPL
));
87 devplcysys_sz
= DEVPLCYSYS_SZ(privimplinfo
);
90 (char *)DEVPLCYSYS_RDP((devplcysys_t
*)0, privimplinfo
) -
93 (char *)DEVPLCYSYS_WRP((devplcysys_t
*)0, privimplinfo
) -
98 * Read a configuration file line and return a static buffer pointing to it.
99 * It returns a static struct fileentry which has several fields:
100 * - rawbuf, which includes the lines including empty lines and comments
101 * leading up to the file and the entry as found in the file
102 * - orgentry, pointer in rawbuf to the start of the entry proper.
103 * - entry, a pre-parsed entry, escaped newlines removed.
104 * - startline, the line number of the first line in the file
109 static size_t sz
= BUFSIZ
;
110 static struct fileentry fe
;
111 static int linecnt
= 1;
113 char *buf
= fe
.rawbuf
;
119 fe
.rawbuf
= buf
= malloc(sz
);
123 if (fe
.entry
!= NULL
) {
125 fe
.orgentry
= fe
.entry
= NULL
;
132 while (lastc
= c
, (c
= getc(fp
)) != EOF
) {
137 fe
.rawbuf
= buf
= realloc(buf
, sz
);
144 /* Newline, escaped or not yet processing an entry */
145 if (off
== -1 || lastc
== '\\')
147 } else if (lastc
== '\n' && off
== -1) {
148 /* Start of more comments */
151 /* Found start of entry */
153 fe
.startline
= linecnt
;
159 fe
.orgentry
= buf
+ off
;
160 p
= fe
.entry
= strdup(fe
.orgentry
);
165 /* Remove <backslash><newline> */
166 if ((p
= strchr(p
, '\\')) != NULL
) {
167 for (off
= 0; (p
[-off
] = p
[0]) != '\0'; p
++)
168 if (p
[0] == '\\' && p
[1] == '\n') {
175 if (lastc
!= '\n' || off
!= -1)
183 * Parse minor number ranges:
184 * (minor) or (lowminor-highminor)
185 * Return 0 for success, -1 for failure.
188 parse_minor_range(const char *range
, minor_t
*lo
, minor_t
*hi
, char *type
)
197 tmp
= strtoul(range
, &p
, 0);
198 if (tmp
> L_MAXMIN32
|| (tmp
== 0 && errno
!= 0) ||
199 (*p
!= '-' && *p
!= ')'))
204 tmp
= strtoul(p
+ 1, &p
, 0);
205 if (tmp
> L_MAXMIN32
|| (tmp
== 0 && errno
!= 0) || *p
!= ')')
231 put_minor_range(FILE *fp
, fileentry_t
*old
, const char *devn
, const char *tail
,
232 minor_t lo
, minor_t hi
, char type
)
234 /* Preserve preceeding comments */
235 if (old
!= NULL
&& old
->rawbuf
!= old
->orgentry
)
236 (void) fwrite(old
->rawbuf
, 1, old
->orgentry
- old
->rawbuf
, fp
);
239 put_minor_range(fp
, NULL
, devn
, tail
, lo
, hi
, 'b');
240 put_minor_range(fp
, NULL
, devn
, tail
, lo
, hi
, 'c');
241 } else if (lo
== hi
) {
242 (void) fprintf(fp
, "%s:(%d)%c%s", devn
, (int)lo
, type
, tail
);
244 (void) fprintf(fp
, "%s:(%d-%d)%c%s", devn
, (int)lo
, (int)hi
,
250 delete_one_entry(const char *filename
, const char *entry
)
252 char tfile
[MAXPATHLEN
];
253 char ofile
[MAXPATHLEN
];
265 mpart
= strchr(entry
, ':');
273 if (parse_minor_range(mpart
, &rlo
, &rhi
, &rtype
) != 0)
281 if (strlen(filename
) + sizeof (XEND
) > sizeof (tfile
))
284 old
= fopen(filename
, "r");
289 (void) snprintf(tfile
, sizeof (tfile
), "%s%s", filename
, XEND
);
290 (void) snprintf(ofile
, sizeof (ofile
), "%s%s", filename
, ".old");
292 nfile
= mktemp(tfile
);
294 new = fopen(nfile
, "w");
302 /* Copy permissions, ownership */
303 if (fstat(fileno(old
), &buf
) == 0) {
304 (void) fchown(newfd
, buf
.st_uid
, buf
.st_gid
);
305 (void) fchmod(newfd
, buf
.st_mode
);
307 (void) fchown(newfd
, 0, 3); /* root:sys */
308 (void) fchmod(newfd
, 0644);
311 while ((fep
= fgetline(old
))) {
318 /* Trailing comments */
319 if (fep
->entry
== NULL
) {
320 (void) fputs(fep
->rawbuf
, new);
325 while (*tok
&& isspace(*tok
))
329 (void) fputs(fep
->rawbuf
, new);
333 /* Make sure we can recover the remainder incl. whitespace */
334 tail
= strpbrk(tok
, "\t\n ");
336 tail
= tok
+ strlen(tok
);
340 if (delall
|| delrange
) {
341 min
= strchr(tok
, ':');
352 * Delete or shrink overlapping ranges.
354 if (strncmp(entry
, tok
, len
) == 0 &&
357 parse_minor_range(min
, &lo
, &hi
, &type
) == 0 &&
358 (type
== rtype
|| rtype
== '\0') &&
359 lo
<= rhi
&& hi
>= rlo
) {
360 minor_t newlo
, newhi
;
362 /* Complete overlap, then drop it. */
363 if (lo
>= rlo
&& hi
<= rhi
)
366 /* Partial overlap, shrink range */
376 /* restore NULed character */
382 * We have two ranges:
383 * lo ... newhi (== rlo - 1)
384 * newlo (== rhi + 1) .. hi
386 put_minor_range(new, fep
, tok
, tail
,
388 put_minor_range(new, NULL
, tok
, tail
,
391 put_minor_range(new, fep
, tok
, tail
,
396 } else if (strcmp(entry
, tok
) == 0 ||
397 (strncmp(entry
, tok
, len
) == 0 &&
399 entry
[len
+1] == '*' &&
400 entry
[len
+2] == '\0')) {
402 * Delete exact match.
407 /* Copy unaffected entry. */
408 (void) fputs(fep
->rawbuf
, new);
413 if (ferror(new) == 0 && fclose(new) == 0 && fep
!= NULL
) {
414 if (rename(filename
, ofile
) != 0) {
416 (void) fprintf(stderr
, gettext(ERR_UPDATE
), ofile
);
417 (void) unlink(ofile
);
418 (void) unlink(nfile
);
420 } else if (rename(nfile
, filename
) != 0) {
422 (void) fprintf(stderr
, gettext(ERR_UPDATE
), ofile
);
423 (void) rename(ofile
, filename
);
424 (void) unlink(nfile
);
427 (void) unlink(ofile
);
429 (void) unlink(nfile
);
435 delete_plcy_entry(const char *filename
, const char *entry
)
441 copy
= strdup(entry
);
445 for (single
= strtok_r(copy
, " \t\n", &p
);
447 single
= strtok_r(NULL
, " \t\n", &p
)) {
448 if ((ret
= delete_one_entry(filename
, single
)) != 0) {
458 * Analyze the device policy token; new tokens should be added to
459 * toktab; new token types should be coded here.
462 parse_plcy_token(char *token
, devplcysys_t
*dp
)
464 char *val
= strchr(token
, '=');
470 (void) fprintf(stderr
, gettext(ERR_NO_EQUALS
), token
);
475 for (i
= 0; i
< NTOK
; i
++) {
476 if (strcmp(token
, toktab
[i
].token
) == 0) {
477 /* standard pointer computation for tokens */
478 void *item
= (char *)dp
+ toktab
[i
].off
;
480 switch (toktab
[i
].type
) {
482 pset
= priv_str_to_set(val
, ",", &perr
);
485 (void) fprintf(stderr
,
486 gettext(ERR_NO_MEM
));
488 (void) fprintf(stderr
,
489 gettext(ERR_BAD_PRIVS
),
490 perr
- val
, val
, perr
);
493 priv_copyset(pset
, item
);
497 (void) fprintf(stderr
,
498 "Internal Error: bad token type: %d\n",
502 /* Standard cleanup & return for good tokens */
507 (void) fprintf(stderr
, gettext(ERR_BAD_TOKEN
), token
);
512 add2str(char **dstp
, const char *str
, size_t *sz
)
515 size_t len
= strlen(p
) + strlen(str
) + 1;
521 *dstp
= p
= realloc(p
, *sz
);
523 (void) fprintf(stderr
, gettext(ERR_NO_MEM
));
527 (void) strcat(p
, str
);
532 * Verify that the policy entry is valid and return the canonical entry.
535 check_plcy_entry(char *entry
, const char *driver
, boolean_t todel
)
540 size_t sz
= strlen(entry
) * 2 + strlen(driver
) + 3;
541 boolean_t tokseen
= B_FALSE
;
546 ds
= alloca(devplcysys_sz
);
548 if (res
== NULL
|| ds
== NULL
) {
549 (void) fprintf(stderr
, gettext(ERR_NO_MEM
));
555 while ((tok
= strtok(entry
, " \t\n")) != NULL
) {
558 /* It's not a token */
559 if (strchr(tok
, '=') == NULL
) {
560 if (strchr(tok
, ':') != NULL
) {
561 (void) fprintf(stderr
, gettext(ERR_BAD_MINOR
));
565 if (*res
!= '\0' && add2str(&res
, "\n", &sz
) != 0)
570 if (parse_minor_range(tok
, &ds
->dps_lomin
,
571 &ds
->dps_himin
, &type
) != 0 ||
572 (!todel
&& type
== '\0')) {
573 (void) fprintf(stderr
,
574 gettext(ERR_BAD_MINOR
));
579 char *tmp
= strchr(tok
, '*');
582 strchr(tmp
+ 1, '*') != NULL
) {
583 (void) fprintf(stderr
,
584 gettext(ERR_BAD_MINOR
));
589 if (add2str(&res
, driver
, &sz
) != 0)
591 if (add2str(&res
, ":", &sz
) != 0)
593 if (add2str(&res
, tok
, &sz
) != 0)
598 if (add2str(&res
, driver
, &sz
) != 0)
600 if (add2str(&res
, ":*", &sz
) != 0)
603 if (parse_plcy_token(tok
, ds
) != 0) {
608 if (add2str(&res
, "\t", &sz
) != 0)
610 if (add2str(&res
, tok
, &sz
) != 0)
615 if (todel
&& tokseen
|| *res
== '\0' || !todel
&& !tokseen
) {
616 (void) fprintf(stderr
, gettext(ERR_INVALID_PLCY
));
621 if (add2str(&res
, "\n", &sz
) != 0)
627 update_device_policy(const char *filename
, const char *entry
, boolean_t repl
)
632 char *dup
, *tok
, *s1
;
636 (void) fprintf(stderr
, gettext(ERR_NO_MEM
));
641 * Split the entry in lines; then get the first token
644 for (tok
= strtok_r(dup
, "\n", &s1
); tok
!= NULL
;
645 tok
= strtok_r(NULL
, "\n", &s1
)) {
647 tok
= strtok(tok
, " \n\t");
649 if (delete_one_entry(filename
, tok
) != 0) {
658 fp
= fopen(filename
, "a");
662 (void) fputs(entry
, fp
);
664 if (fflush(fp
) != 0 || fsync(fileno(fp
)) != 0 || fclose(fp
) != 0)
672 * We need to allocate the privileges now or the privilege set
673 * parsing code will not allow them.
676 check_priv_entry(const char *privlist
, boolean_t add
)
678 char *l
= strdup(privlist
);
682 (void) fprintf(stderr
, gettext(ERR_NO_MEM
));
686 while ((pr
= strtok_r(l
, ",", &l
)) != NULL
) {
687 /* Privilege already exists */
688 if (priv_getbyname(pr
) != -1)
691 if (add
&& modctl(MODALLOCPRIV
, pr
) != 0) {
692 (void) fprintf(stderr
, gettext(ERR_BAD_PRIV
), pr
,