devalloc.c revision 10ddde3aee60d88fa580028fcf7642a87e80a2c6
/*
* 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
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <limits.h>
#include <fcntl.h>
#include <utime.h>
#include <synch.h>
#include <strings.h>
#include <string.h>
#include <libintl.h>
#include <errno.h>
#include <auth_list.h>
#include <bsm/devalloc.h>
#define DA_DEFS "/etc/security/tsol/devalloc_defaults"
extern int _readbufline(char *, int, char *, int, int *);
extern char *strtok_r(char *, const char *, char **);
extern char *_strtok_escape(char *, char *, char **);
extern int getdaon(void);
extern int da_matchname(devalloc_t *, char *);
extern int dmap_matchname(devmap_t *, char *);
/*
* The following structure is for recording old entries to be retained.
* We read the entries from the database into a linked list in memory,
* then turn around and write them out again.
*/
typedef struct strentry {
} strentry_t;
/*
* da_check_longindevperm -
* reads /etc/logindevperm and checks if specified device is in the file.
* returns 1 if specified device found in /etc/logindevperm, else returns 0
*/
int
da_check_logindevperm(char *devname)
{
int ret = 0;
int fd = -1;
char *field_delims = " \t\n";
/*
* check if /etc/logindevperm exists and get its size
*/
return (0);
return (0);
}
return (0);
}
return (0);
}
/*
* read and parse /etc/logindevperm
*/
lineno++;
continue; /* ignore blank lines */
/* invalid entry */
continue;
/* empty device list */
continue;
if (plen == 0)
else
fbuf[0] = '\0';
return (slen);
}
}
/*
* check if devname exists in /etc/logindevperm
*/
/*
* device and devname may be one of these types -
*/
return (1);
}
/* all wildcard types */
*ptr = '\0';
return (1);
}
}
}
return (ret);
}
/*
* _da_read_file -
* contents changed since the last time we read it.
* returns size of buffer read, or -1 on failure.
*/
int
int flag)
{
int fd = -1;
int fsize = 0;
*ftime = 0;
/* check the size and the time stamp on the file */
return (-1);
return (-1);
}
/*
* file has been modified since we last read it; or this
* is a forced read.
* read file into the buffer with rw lock.
*/
return (-1);
return (-1);
}
}
return (-1);
}
return (-1);
}
/*
* verify that the file did not change just after we read it.
*/
return (-1);
}
return (-1);
}
}
return (fsize);
}
/*
* _update_zonename -
*/
void
{
int i, j;
int has_zonename = 0;
char *zonename;
return;
return;
}
}
has_zonename = 1;
return;
zonename++;
if (has_zonename) {
return;
}
newsize += 1;
if (has_zonename) {
newsize -= 1;
if (newsize == 0) {
/*
* put 'reserved' in the empty slot.
*/
return;
}
} else {
return;
}
}
for (i = 0, j = 0; i < oldsize; i++) {
continue;
j++;
}
}
}
/*
* _dmap2str -
* converts a device_map entry into a printable string
* returns 0 on success, -1 on error.
*/
/*ARGSUSED*/
static int
{
int length;
return (-1);
return (-1);
dmp->dmap_devlist);
return (-1);
return (0);
}
/*
* _dmap2strentry -
* calls dmap2str to break given devmap_t into printable entry.
* returns pointer to decoded entry, NULL on error.
*/
static strentry_t *
{
return (NULL);
KV_TOKEN_DELIMIT"\\\n\t") != 0) {
return (NULL);
}
return (sep);
}
/*
* fix_optstr -
* removes trailing ':' from buf.
*/
void
fix_optstr(char *buf)
{
char *p = NULL;
*p = ';';
}
/*
* _da2str -
* converts a device_allocate entry into a printable string
* returns 0 on success, -1 on error.
*/
static int
const char *osep)
{
int length;
int matching_entry = 0;
char **dnames;
matching_entry = 1;
break;
}
}
}
return (-1);
return (-1);
if (matching_entry)
DA_RESERVED, sep);
} else {
return (-1);
}
if (dap->da_devopts)
return (-1);
DA_RESERVED, sep);
return (-1);
return (-1);
return (-1);
return (0);
}
/*
* _da2strentry -
* calls da2str to break given devalloc_t into printable entry.
* returns pointer to decoded entry, NULL on error.
*/
static strentry_t *
{
return (NULL);
return (NULL);
}
return (sep);
}
/*
* _def2str
* converts da_defs_t into a printable string.
* returns 0 on success, -1 on error.
*/
static int
{
int length;
return (-1);
KV_ASSIGN, KV_DELIMITER) != 0)
return (-1);
}
return (-1);
return (0);
}
/*
* _def2strentry
* calls _def2str to break given da_defs_t into printable entry.
* returns pointer decoded entry, NULL on error.
*/
static strentry_t *
{
return (NULL);
KV_TOKEN_DELIMIT) != 0) {
return (NULL);
}
return (sep);
}
/*
* _build_defattrs
* cycles through all defattr entries, stores them in memory. removes
* entries with the given search_key (device type).
* returns 0 if given entry not found, 1 if given entry removed, 2 on
* error.
*/
static int
{
int rc = 0;
setdadefent();
/*
* During DA_ADD, we keep an existing entry unless
* we have DA_FORCE set to override that entry.
*/
rc = 0;
}
if (rc == 0) {
enddadefent();
return (2);
}
/* retaining defattr entry: tmp_str->se_str */
if (*head_defent == NULL) {
} else {
}
}
}
enddadefent();
return (rc);
}
/*
* _build_lists -
* cycles through all the entries, stores them in memory. removes entries
* with the given search_key (device name or type).
* returns 0 if given entry not found, 1 if given entry removed, 2 on
* error.
*/
static int
{
int rc = 0;
goto dmap_only;
/* build device_allocate */
setdaent();
/*
* During DA_ADD, we keep an existing entry unless
* we have DA_FORCE set to override that entry.
*/
rc = 0;
}
if (rc == 0) {
enddaent();
return (2);
}
/* retaining devalloc entry: tmp_str->se_str */
if (*head_devallocp == NULL) {
} else {
}
}
}
enddaent();
return (rc);
/* build device_maps */
rc = 0;
setdmapent();
/*
* During DA_ADD, we keep an existing entry unless
* we have DA_FORCE set to override that entry.
*/
rc = 0;
}
if (rc == 0) {
enddmapent();
return (2);
}
/* retaining devmap entry: tmp_str->se_str */
if (*head_devmapp == NULL) {
} else {
}
}
}
enddmapent();
return (rc);
}
/*
* _write_defattrs
* writes current entries to devalloc_defaults.
*/
static void
{
}
}
/*
* _write_device_allocate -
* writes current entries in the list to device_allocate.
*/
static void
{
int is_on = -1;
/*
* put it back before anything else.
* we need to check for the string only if the file
* exists.
*/
if (is_on == 0)
else if (is_on == 1)
}
while (tmp_str) {
}
}
/*
* _write_device_maps -
* writes current entries in the list to device_maps.
*/
static void
{
while (tmp_str) {
}
}
/*
* _write_new_defattrs
* writes the new entry to devalloc_defaults.
* returns 0 on success, -1 on error.
*/
static int
{
int count;
char *lasts;
return (-1);
return (0);
count = 1;
}
if (count)
count++;
}
} else {
}
return (0);
}
/*
* _write_new_entry -
* writes the new devalloc_t to device_allocate or the new devmap_t to
* device_maps.
* returns 0 on success, -1 on error.
*/
static int
{
int count;
char *lasts;
if (flag & DA_MAPS_ONLY)
goto dmap_only;
return (-1);
} else {
NULL) {
count = 1;
}
if (count)
KV_TOKEN_DELIMIT "\\\n\t");
count++;
}
if (count)
KV_DELIMITER "\\\n\t");
} else {
KV_DELIMITER "\\\n\t");
}
}
if (flag & DA_ALLOC_ONLY)
return (0);
return (-1);
return (0);
}
/*
* _da_lock_devdb -
* locks the database files; lock can be either broken explicitly by
* closing the fd of the lock file, or it expires automatically at process
* termination.
* returns fd of the lock file or -1 on error.
*/
int
_da_lock_devdb(char *rootdir)
{
int lockfd = -1;
int ret;
int count = 0;
int retry = 10;
int retry_sleep;
char *lockfile;
char path[MAXPATHLEN];
} else {
path[0] = '\0';
return (-1);
}
/* cannot open lock file */
return (-1);
/* cannot position lock file */
return (-1);
}
errno = 0;
while (retry > 0) {
count++;
if (ret == 0) {
return (lockfd);
}
/* cannot set lock */
return (-1);
}
retry--;
(void) sleep(retry_sleep);
errno = 0;
}
return (-1);
}
/*
* da_open_devdb -
* opens one or both database files - device_allocate, device_maps - in
* the specified mode.
* locks the database files; lock is either broken explicitly by the
* caller by closing the lock file fd, or it expires automatically at
* process termination.
* writes the file pointer of opened file in the input args - dafp, dmfp.
* returns fd of the lock file on success, -2 if database file does not
* exist, -1 on other errors.
*/
int
{
int oflag = 0;
int fda = -1;
int fdm = -1;
int lockfd = -1;
char *fname;
char *fmode;
char path[MAXPATHLEN];
return (-1);
fmode = "r+F";
fmode = "rF";
}
return (-1);
goto dmap_only;
path[0] = '\0';
/*
* open the device allocation file
*/
} else {
if (lockfd != -1)
return (-1);
}
}
if (lockfd != -1)
}
if (lockfd != -1)
return (-1);
}
if ((flag & DA_ALLOC_ONLY))
goto out;
path[0] = '\0';
/*
* open the device map file
*/
} else {
if (lockfd != -1)
return (-1);
}
}
if (lockfd != -1)
}
if (lockfd != -1)
return (-1);
}
out:
return (lockfd);
}
/*
* _record_on_off -
* adds either DA_ON_STR or DA_OFF_STR to device_allocate
* returns 0 on success, -1 on error.
*/
static int
{
int dafd;
int nsize;
int nitems = 1;
int actionlen;
int str_found = 0;
char *actionstr;
else
return (-1);
str_found = 1;
}
}
/*
* the file never had either the on or the off string;
* make room for it.
*/
str_found = 0;
}
return (-1);
nbuf[0] = '\0';
/* now put the first line that we read in fgets */
return (-1);
}
}
/* now get the rest of the old file */
return (-1);
}
}
return (-1);
}
return (0);
}
/*
* da_update_defattrs -
* writes default attributes to devalloc_defaults
* returns 0 on success, -1 on error.
*/
int
{
char *tmpdefpath = TMPATTRS;
return (0);
return (-1);
return (-1);
}
(void) unlink(tmpdefpath);
return (-1);
}
/*
* examine all entries, remove an old one if required, check
* if a new one needs to be added.
*/
if (rc == 1) {
(void) unlink(tmpdefpath);
return (rc);
}
}
}
/*
* write back any existing entries.
*/
/* add new entries */
} else {
}
rc = -1;
(void) unlink(tmpdefpath);
}
return (rc);
}
/*
* da_update_device -
* writes devices entries to device_allocate and device_maps.
* returns 0 on success, -1 on error.
*/
int
{
int rc;
int lockfd = -1;
return (0);
/*
* device_allocate and device_maps. updates can be
* done in both or either of the files.
*/
return (0);
}
/*
* name, type and list are required fields for adding a new
* device.
*/
return (-1);
}
return (-1);
return (-1);
return (-1);
return (-1);
}
} else {
}
goto dmap_only;
/*
* device_allocation.
*/
else
if (lockfd == -1)
return (-1);
return (-1);
}
return (-1);
}
/*
* We don't need to parse the file if we are here just to record
*/
return (-1);
}
goto out;
}
/*
* examine all the entries, remove an old one if forced to,
* and check that they are suitable for updating.
* we need to do this only if the file exists already.
*/
&head_devmapp)) != 0) {
if (rc != 1) {
return (rc);
}
}
}
/*
* write back any existing devalloc entries, along with
*/
goto out;
return (-1);
}
return (-1);
}
/* write back any existing devmap entries */
if (head_devmapp != NULL)
out:
/* add any new entries */
if (rc == 0)
} else {
if (tafp)
if (tmfp)
}
rc = 0;
rc = -1;
}
}
rc = -1;
}
}
return (rc);
}
/*
* da_add_list -
* adds new /dev link name to the linked list of devices.
* returns 0 if link added successfully, -1 on error.
*/
int
{
int instance;
int new_entry = 0;
char dname[DA_MAXNAME];
return (-1);
dname[0] = '\0';
tname = DA_CD_NAME;
dtype = DA_CD_TYPE;
} else {
return (-1);
}
/*
* Add the new link name to the list of links
* that the device 'dname' has.
*/
break;
}
/*
* Either this is the first entry ever, or no matching entry
* was found. Create a new one and add to the list.
*/
instance = 0;
else /* no matching entry */
instance++;
NULL)
return (-1);
new_entry = 1;
/*
* Look for default label range, authorizations and cleaning
* program in devalloc_defaults. If label range is not
* specified in devalloc_defaults, assume it to be admin_low
* to admin_high.
*/
setdadefent();
}
enddadefent();
+ 1; /* +1 for terminator */
}
} else {
plen = 0;
}
if (new_entry) {
}
return (-1);
}
if (plen == 0)
else
" %s", link);
/*
* This is the first entry of this device type.
*/
}
return (0);
}
/*
* da_remove_list -
* removes a /dev link name from the linked list of devices.
* returns type of device if link for that device removed
* successfully, else returns -1 on error.
* if all links for a device are removed, stores that device
* name in devname.
*/
int
{
int flag;
int remove_dev = 0;
return (-1);
else
switch (type) {
case DA_AUDIO:
break;
case DA_CD:
break;
case DA_FLOPPY:
break;
case DA_TAPE:
break;
case DA_RMDISK:
break;
default:
return (-1);
}
remove_dev = 1;
goto remove_dev;
}
}
}
return (-1);
}
/* last name in the list */
remove_dev = 1;
break;
}
}
return (-1);
}
continue;
if (plen == 0) {
slen =
} else {
slen =
}
}
break;
}
}
if (remove_dev == 1) {
}
/*
* what we removed above was the first entry
* in the list. make the next entry to be the
* first.
*/
} else {
/*
* the matching entry was the only entry in the list
* for this type.
*/
}
}
return (flag);
}
/*
* da_is_on -
* checks if device allocation feature is turned on.
* returns 1 if on, 0 if off, -1 if status string not
* found in device_allocate.
*/
int
da_is_on()
{
return (getdaon());
}
/*
* da_print_device -
* debug routine to print device entries.
*/
void
{
else
return;
}
}