devinfo_devperm.c revision ceeba6f9f0adf370c2a0f5c81a0d6ef1ba146cb4
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
#define _POSIX_PTHREAD_SEMANTICS /* for getgrnam_r */
#ifdef lint
#define _REENTRANT /* for strtok_r */
#endif
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
#include <grp.h>
#include <pwd.h>
#include <nss_dbdefs.h>
#include <stdarg.h>
#include <syslog.h>
#include <sys/devinfo_impl.h>
#include <libnvpair.h>
#include <device_info.h>
#include <regex.h>
#include <strings.h>
#include <libdevinfo.h>
#include <zone.h>
#include <fcntl.h>
#include <utmpx.h>
extern int is_minor_node(const char *, const char **);
static int is_login_user(uid_t);
void (*)());
static void logerror(char *);
static int is_blank(char *);
#define MAX_LINELEN 256
#define LOGINDEVPERM "/etc/logindevperm"
/*
* Revoke all access to a device node and make sure that there are
* no interposed streams devices attached. Must be called before a
* device is actually opened.
* When fdetach is called, the underlying device node is revealed; it
* will have the previous owner and that owner can re-attach; so we
* retry until we win.
* Ignore non-existent devices.
*/
static int
void (*errmsg)(char *))
{
int err = 0, local_errno;
char errstring[MAX_LINELEN];
return (0);
err = -1;
local_errno = errno;
}
/*
* don't fdetach block devices, as it will unmount them
*/
err = -1;
local_errno = errno;
}
}
"failed to chown device %s: %s\n",
}
}
/*
*/
if (err != 0) {
/*
* If the file system returned ENOSYS, we know that it
* doesn't support ACLs, therefore, we must assume that
* there were no ACLs to remove in the first place.
*/
err = 0;
err = -1;
if (errmsg) {
"failed to set acl on device %s: %s\n",
}
}
err = -1;
if (errmsg) {
"failed to chmod device %s: %s\n",
}
}
}
return (err);
}
/*
* logindevperm - change owner/group/permissions of devices
* list in /etc/logindevperm.
*/
static int
{
const char *field_delims = " \t\n";
char saveline[MAX_LINELEN];
char *console;
char *mode_str;
char *dev_list;
char *device;
char *ptr;
int mode;
int n;
if (errmsg) {
LOGINDEVPERM ": open failed: %s\n",
}
return (-1);
}
return (-1);
ttyn_path[n] = '\0';
char *last;
lineno++;
continue; /* ignore blank lines */
continue;
tmp[n] = '\0';
continue;
if (errmsg) {
": line %d, invalid entry -- %s\n",
}
continue;
}
/* convert string to octal value */
if (errmsg) {
": line %d, invalid mode -- %s\n",
}
continue;
}
if (errmsg) {
": line %d, empty device list -- %s\n",
}
continue;
}
err = -1;
err = -1;
}
}
}
return (err);
}
/*
* returns 0 if resolved, -1 otherwise.
* devpath: Absolute path to /dev link
*/
int
{
char *ptr;
int linksize;
char *slashdev = "/dev/";
if (devfs_path) {
*devfs_path = NULL;
}
if (linksize <= 0) {
return (-1);
} else {
}
/*
* if the link contents is not a minor node assume
* that link contents is really a pointer to another
* link, and if so recurse and read its link contents.
*/
1) {
/* absolute path, starting with /dev */
} else {
/* relative path, prefix devpath */
/* invalid link */
return (-1);
}
*ptr = '\0';
*ptr = '/';
}
}
if (devfs_path) {
if (*devfs_path == NULL) {
return (-1);
}
}
return (0);
}
/*
* check a logindevperm line for a driver list and match this against
* the driver of the minor node
* returns 0 if no drivers were specified or a driver match
*/
static int
{
char *devfs_path = NULL;
char saveline[MAX_LINELEN];
char *p;
char *p;
/* truncate on : so we can take a snapshot */
*p = '\0';
if (node) {
} else {
return (0);
}
} else {
return (0);
}
if (p == NULL) {
return (0);
}
if (driver) {
while (driver) {
return (0);
}
}
}
}
return (-1);
}
/*
*/
static int
{
int changed = 0;
char pwd_buf[NSS_BUFLEN_PASSWD];
return (0);
}
setutxent();
changed = 1;
break;
}
}
endutxent();
return (changed);
}
/*
* in a directory.
* This function is recursive. We start with "/" and the rest of the pathname
* in left_to_do argument, and we walk the entire pathname which may contain
* regular expressions or '*' for each directory name or basename.
*/
static int
{
int err = 0;
char errstring[MAX_LINELEN];
char *p;
int alwaysmatch = 0;
char *match;
/*
* Determine if the search needs to be performed via finddev,
* which returns only persisted names in the global /dev, or
* readdir, for paths other than /dev and non-global zones.
* This use of finddev avoids triggering potential implicit
* reconfig for names managed by logindevperm but not present
* on the system.
*/
if (!device_exists(path)) {
return (-1);
}
/*
* ENOENT errors are expected errors when there are
* dangling /dev device links. Ignore them silently
*/
return (0);
}
if (errmsg) {
"failed to stat %s: %s\n", path,
}
return (-1);
} else {
if (strlen(left_to_do) == 0) {
/* finally check the driver matches */
/*
* if the owner of device has been
* login, the ownership and mode
* should be set already. in
* this case, do not set the
* permissions.
*/
return (0);
}
/* we are done, set the permissions */
if (setdevaccess(path,
return (-1);
}
}
}
return (0);
}
}
return (0);
alwaysmatch = 0;
return (-1);
}
return (-1);
}
/* transform pattern into ^pattern$ for exact match */
MAXPATHLEN + 2) {
return (-1);
}
alwaysmatch = 1;
} else {
return (-1);
}
}
if (alwaysmatch ||
} else {
}
/*
* recurse but adjust what is still left to do
*/
remainder_path = (p ?
err = -1;
}
}
}
if (!alwaysmatch) {
}
return (err);
}
/*
* di_devperm_login - modify access of devices in /etc/logindevperm
* by changing owner/group/permissions to that of ttyn.
*/
int
void (*errmsg)(char *))
{
int err;
char grbuf[NSS_BUFLEN_GROUP];
(*errmsg)("di_devperm_login: NULL tty device\n");
return (-1);
}
} else {
/*
* this should never happen, but if it does set
* group to tty's traditional value.
*/
tty_gid = 7;
}
/* set the login console device permission */
if (err) {
return (err);
}
/* set the device permissions */
}
/*
* di_devperm_logout - clean up access of devices in /etc/logindevperm
* by resetting owner/group/permissions.
*/
int
di_devperm_logout(const char *ttyn)
{
return (-1);
} else {
/*
* this should never happen, but if it does set user
* and group to root's traditional values.
*/
root_uid = 0;
root_gid = 0;
}
}
static void
{
}
/*
* Tokens are separated by ' ', '\t', ':', '=', '&', '|', ';', '\n', or '\0'
*/
static int
{
char *cp;
char *cp1;
char *tokenp;
cp++; /* skip leading spaces */
}
cp++; /* point to next character */
}
/*
* If terminating character is a space or tab, look ahead to see if
* there's another terminator that's not a space or a tab.
* (This code handles trailing spaces.)
*/
;
}
}
if (*tchar == '\0') {
*tchar = '\n';
}
}
return (0);
}
return (1);
}
/*
* get a decimal octal or hex number. Handle '~' for one's complement.
*/
static int
{
int radix;
int retval = 0;
int onescompl = 0;
int negate = 0;
char c;
if (*token == '~') {
onescompl++; /* perform one's complement on result */
token++;
} else if (*token == '-') {
negate++;
token++;
}
if (*token == '0') {
token++;
c = *token;
if (c == '\0') {
*valuep = 0; /* value is 0 */
return (0);
}
if (c == 'x' || c == 'X') {
radix = 16;
token++;
} else {
radix = 8;
}
} else
radix = 10;
while ((c = *token++)) {
switch (radix) {
case 8:
if (c >= '0' && c <= '7') {
c -= '0';
} else {
/* invalid number */
return (0);
}
break;
case 10:
if (c >= '0' && c <= '9') {
c -= '0';
} else {
/* invalid number */
return (0);
}
break;
case 16:
if (c >= 'a' && c <= 'f') {
c = c - 'a' + 10;
} else if (c >= 'A' && c <= 'F') {
c = c - 'A' + 10;
} else if (c >= '0' && c <= '9') {
c -= '0';
} else {
/* invalid number */
return (0);
}
break;
}
}
if (onescompl) {
}
if (negate) {
}
return (1);
}
/*
* Read /etc/minor_perm, return mperm list of entries
*/
struct mperm *
{
char line[MAX_MINOR_PERM_LINE];
char *cp, *p, t;
int ln = 0;
/*
*/
} else {
(*errcb)(MP_CANT_FIND_USER_ERR, 0);
}
} else {
(*errcb)(MP_CANT_FIND_GROUP_ERR, 0);
}
return (NULL);
}
ln++;
/* cut off comments starting with '#' */
*cp = '\0';
/* ignore comment or blank lines */
continue;
continue;
}
/* sanity-check */
continue;
}
continue;
} else if (t == '\n' || t == '\0') {
continue;
}
if (t == ':') {
}
continue;
}
} else {
}
if (t == '\n' || t == '\0') {
continue;
}
goto link;
}
goto link;
}
if (t == '\n' || t == '\0') { /* no owner or group */
goto link;
}
goto link;
}
continue;
} else if (t == '\n' || t == '\0') { /* no group */
goto link;
}
goto link;
}
continue;
}
link:
/*
* We only want the minor perm entry for a
* the named driver. The driver name is the
* minor in the clone case.
*/
continue;
}
} else {
continue;
}
}
}
if (minor_perms == NULL) {
minor_perms = mp;
} else {
}
/*
* Compute the uid's and gid's here - there are
* fewer lines in the /etc/minor_perm file than there
* are devices to be stat(2)ed. And almost every
* device is 'root sys'. See 1135520.
*/
} else {
}
} else {
}
}
}
return (minor_perms);
}
struct mperm *
{
}
static struct mperm *
{
}
/*
* Free mperm list of entries
*/
void
{
if (mp->mp_drvname)
if (mp->mp_minorname)
}
}
static int
{
int err;
if (err != 0)
return (err);
if (err != 0)
return (err);
if (err != 0)
return (err);
return (err);
}
static nvlist_t *
void (*errcb)(minorperm_err_t, int))
{
int err;
return (NULL);
}
return (NULL);
}
}
return (nvl);
}
/*
* Load all minor perm entries into the kernel
* Done at boot time via devfsadm
*/
int
void (*errcb)(minorperm_err_t, int))
{
int err;
return (-1);
return (-1);
}
return (err);
}
/*
*/
static int
void (*errcb)(minorperm_err_t, int))
{
int err;
char *buf;
return (-1);
return (-1);
}
return (err);
}
int
devfs_add_minor_perm(char *drv,
void (*errcb)(minorperm_err_t, int))
{
}
int
devfs_rm_minor_perm(char *drv,
void (*errcb)(minorperm_err_t, int))
{
}
/*
* is_blank() returns 1 (true) if a line specified is composed of
* whitespace characters only. otherwise, it returns 0 (false).
*
* Note. the argument (line) must be null-terminated.
*/
static int
{
return (0);
return (1);
}