17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 545916cd2Sjpk * Common Development and Distribution License (the "License"). 645916cd2Sjpk * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 2145916cd2Sjpk 227c478bd9Sstevel@tonic-gate /* 23*7248adcbSJan Parcel * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include <auth_attr.h> 277c478bd9Sstevel@tonic-gate #include <auth_list.h> 287c478bd9Sstevel@tonic-gate #include <dirent.h> 297c478bd9Sstevel@tonic-gate #include <errno.h> 307c478bd9Sstevel@tonic-gate #include <fcntl.h> 317c478bd9Sstevel@tonic-gate #include <libintl.h> 327c478bd9Sstevel@tonic-gate #include <locale.h> 337c478bd9Sstevel@tonic-gate #include <pwd.h> 347c478bd9Sstevel@tonic-gate #include <signal.h> 357c478bd9Sstevel@tonic-gate #include <stdio.h> 367c478bd9Sstevel@tonic-gate #include <stdlib.h> 377c478bd9Sstevel@tonic-gate #include <string.h> 3845916cd2Sjpk #include <strings.h> 397c478bd9Sstevel@tonic-gate #include <unistd.h> 407c478bd9Sstevel@tonic-gate #include <bsm/devices.h> 4145916cd2Sjpk #include <sys/acl.h> 4245916cd2Sjpk #include <tsol/label.h> 4345916cd2Sjpk #include <syslog.h> 4445916cd2Sjpk #include <limits.h> 4545916cd2Sjpk #include <user_attr.h> 4645916cd2Sjpk #include <secdb.h> 4745916cd2Sjpk #include <sys/mkdev.h> 487c478bd9Sstevel@tonic-gate #include <sys/acl.h> 497c478bd9Sstevel@tonic-gate #include <sys/file.h> 507c478bd9Sstevel@tonic-gate #include <sys/procfs.h> 517c478bd9Sstevel@tonic-gate #include <sys/param.h> 527c478bd9Sstevel@tonic-gate #include <sys/resource.h> 537c478bd9Sstevel@tonic-gate #include <sys/stat.h> 547c478bd9Sstevel@tonic-gate #include <sys/time.h> 557c478bd9Sstevel@tonic-gate #include <sys/types.h> 567c478bd9Sstevel@tonic-gate #include <sys/wait.h> 5745916cd2Sjpk #include <utime.h> 5845916cd2Sjpk #include <libgen.h> 5945916cd2Sjpk #include <zone.h> 6045916cd2Sjpk #include <nss_dbdefs.h> 6145916cd2Sjpk #include <bsm/devalloc.h> 62facf4a8dSllai1 #include <libdevinfo.h> 637c478bd9Sstevel@tonic-gate #include "allocate.h" 647c478bd9Sstevel@tonic-gate 6545916cd2Sjpk extern void print_error(int, char *); 6645916cd2Sjpk 6745916cd2Sjpk #if defined(DEBUG) || defined(lint) 687c478bd9Sstevel@tonic-gate #define dprintf(s, a) (void) fprintf(stderr, s, a) 697c478bd9Sstevel@tonic-gate #define dperror(s) perror(s) 707c478bd9Sstevel@tonic-gate #else /* !DEBUG */ 7145916cd2Sjpk #define dprintf(s, a) 0 7245916cd2Sjpk #define dperror(s) 0 737c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 747c478bd9Sstevel@tonic-gate 7545916cd2Sjpk #define DEV_ERRORED(sbuf) (((sbuf).st_mode & ~S_IFMT) == ALLOC_ERR_MODE) 7610ddde3aSaj #define DEV_ALLOCATED(sbuf) ((sbuf).st_uid != DA_UID || \ 7745916cd2Sjpk !(((sbuf).st_mode & ~S_IFMT) == DEALLOC_MODE || \ 7810ddde3aSaj DEV_ERRORED(sbuf))) 797c478bd9Sstevel@tonic-gate 8045916cd2Sjpk #define ALLOC_CLEAN "-A" 8145916cd2Sjpk #define DEALLOC_CLEAN "-D" 8245916cd2Sjpk #define DAC_DIR "/etc/security/dev" 837c478bd9Sstevel@tonic-gate #define DEVICE_AUTH_SEPARATOR "," 8445916cd2Sjpk #define LOCALDEVICE "/dev/console" 857c478bd9Sstevel@tonic-gate #define PROCFS "/proc/" 8645916cd2Sjpk #define SFF_NO_ERROR 0x1 8745916cd2Sjpk 8845916cd2Sjpk #define ALLOC_BY_NONE -1 8945916cd2Sjpk #define CHECK_DRANGE 1 9045916cd2Sjpk #define CHECK_URANGE 2 9145916cd2Sjpk #define CHECK_ZLABEL 3 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate extern void audit_allocate_list(char *); 947c478bd9Sstevel@tonic-gate extern void audit_allocate_device(char *); 957c478bd9Sstevel@tonic-gate 9645916cd2Sjpk extern int system_labeled; 977c478bd9Sstevel@tonic-gate extern char *newenv[]; 987c478bd9Sstevel@tonic-gate 9945916cd2Sjpk struct state_file { 10045916cd2Sjpk int sf_flags; 10145916cd2Sjpk char sf_path[MAXPATHLEN]; 10245916cd2Sjpk }; 10345916cd2Sjpk 10445916cd2Sjpk struct file_info { 10545916cd2Sjpk struct stat fi_stat; 10645916cd2Sjpk char *fi_message; 10745916cd2Sjpk }; 10845916cd2Sjpk 10945916cd2Sjpk struct zone_path { 11045916cd2Sjpk int count; 11145916cd2Sjpk char **path; 11245916cd2Sjpk }; 11345916cd2Sjpk 114facf4a8dSllai1 struct dev_names { 11545916cd2Sjpk char **dnames; 11645916cd2Sjpk }; 11745916cd2Sjpk 11845916cd2Sjpk static int _dev_file_name(struct state_file *, devmap_t *); 11910ddde3aSaj static int lock_dev(char *, struct stat *); 12045916cd2Sjpk static int _check_label(devalloc_t *, char *, uid_t, int); 12145916cd2Sjpk static int create_znode(char *, struct zone_path *, devmap_t *); 12245916cd2Sjpk static int remove_znode(char *, devmap_t *); 12345916cd2Sjpk static int update_device(char **, char *, int); 12445916cd2Sjpk 1257c478bd9Sstevel@tonic-gate /* 12645916cd2Sjpk * checks if the invoking user is local to the device 1277c478bd9Sstevel@tonic-gate */ 12845916cd2Sjpk /*ARGSUSED*/ 12945916cd2Sjpk int 13045916cd2Sjpk _is_local(uid_t uid) 1317c478bd9Sstevel@tonic-gate { 13245916cd2Sjpk struct stat statbuf; 1337c478bd9Sstevel@tonic-gate 13445916cd2Sjpk if (stat(LOCALDEVICE, &statbuf) == 0 && 13545916cd2Sjpk statbuf.st_uid == uid) 1367c478bd9Sstevel@tonic-gate return (1); 13745916cd2Sjpk 1387c478bd9Sstevel@tonic-gate return (0); 1397c478bd9Sstevel@tonic-gate } 1407c478bd9Sstevel@tonic-gate 14145916cd2Sjpk /* 14245916cd2Sjpk * Checks if the user with the specified uid has the specified authorization 14345916cd2Sjpk */ 14445916cd2Sjpk int 14545916cd2Sjpk _is_authorized(char *auths, uid_t uid) 1467c478bd9Sstevel@tonic-gate { 14745916cd2Sjpk char *dcp, *authlist, *lasts; 14845916cd2Sjpk char pw_buf[NSS_BUFLEN_PASSWD]; 14945916cd2Sjpk struct passwd pw_ent; 1507c478bd9Sstevel@tonic-gate 15145916cd2Sjpk /* 15245916cd2Sjpk * first, the easy cases 15345916cd2Sjpk */ 15445916cd2Sjpk if (strcmp(auths, "@") == 0) 15545916cd2Sjpk return (1); 15645916cd2Sjpk if (strcmp(auths, "*") == 0) 15745916cd2Sjpk return (ALLOC_BY_NONE); 15845916cd2Sjpk if (getpwuid_r(uid, &pw_ent, pw_buf, sizeof (pw_buf)) == NULL) 15945916cd2Sjpk return (0); 16045916cd2Sjpk if (strpbrk(auths, DEVICE_AUTH_SEPARATOR) == NULL) 16145916cd2Sjpk return (chkauthattr(auths, pw_ent.pw_name)); 16245916cd2Sjpk authlist = strdup(auths); 16345916cd2Sjpk if (authlist == NULL) 16445916cd2Sjpk return (0); 16545916cd2Sjpk for (dcp = authlist; 16645916cd2Sjpk (dcp = strtok_r(dcp, DEVICE_AUTH_SEPARATOR, &lasts)) != NULL; 16745916cd2Sjpk dcp = NULL) { 16845916cd2Sjpk if (chkauthattr(dcp, pw_ent.pw_name)) 16945916cd2Sjpk break; 17045916cd2Sjpk } 17145916cd2Sjpk free(authlist); 1727c478bd9Sstevel@tonic-gate 17345916cd2Sjpk return (dcp != NULL); 1747c478bd9Sstevel@tonic-gate } 17545916cd2Sjpk 17645916cd2Sjpk /* 17745916cd2Sjpk * Checks if the specified user has authorization for the device 17845916cd2Sjpk */ 17945916cd2Sjpk int 18045916cd2Sjpk _is_dev_authorized(devalloc_t *da, uid_t uid) 18145916cd2Sjpk { 18245916cd2Sjpk int ares; 18345916cd2Sjpk char *auth_list, *dcp, *subauth = NULL; 18445916cd2Sjpk 18545916cd2Sjpk auth_list = da->da_devauth; 18645916cd2Sjpk if (auth_list == NULL) 18745916cd2Sjpk return (0); 18845916cd2Sjpk dcp = strpbrk(auth_list, KV_TOKEN_DELIMIT); 18945916cd2Sjpk if (dcp == NULL) 19045916cd2Sjpk return (_is_authorized(auth_list, uid)); 19145916cd2Sjpk if (_is_local(uid)) { 19245916cd2Sjpk /* the local authorization is before the separator */ 19345916cd2Sjpk ares = dcp - auth_list; 19445916cd2Sjpk subauth = malloc(ares + 1); 19545916cd2Sjpk if (subauth == NULL) 19645916cd2Sjpk return (0); 19745916cd2Sjpk (void) strlcpy(subauth, auth_list, (ares + 1)); 19845916cd2Sjpk auth_list = subauth; 19945916cd2Sjpk } else 20045916cd2Sjpk auth_list = dcp + 1; 20145916cd2Sjpk ares = _is_authorized(auth_list, uid); 20245916cd2Sjpk if (subauth != NULL) 20345916cd2Sjpk free(subauth); 20445916cd2Sjpk 20545916cd2Sjpk return (ares); 2067c478bd9Sstevel@tonic-gate } 20745916cd2Sjpk 20845916cd2Sjpk int 20945916cd2Sjpk check_devs(devmap_t *dm) 21045916cd2Sjpk { 21145916cd2Sjpk int status = 0; 21245916cd2Sjpk char **file; 21345916cd2Sjpk 21445916cd2Sjpk if (dm->dmap_devarray == NULL) 21545916cd2Sjpk return (NODMAPERR); 21645916cd2Sjpk for (file = dm->dmap_devarray; *file != NULL; file++) { 21745916cd2Sjpk if ((status = access(*file, F_OK)) == -1) { 21845916cd2Sjpk dprintf("Unable to access file %s\n", *file); 21945916cd2Sjpk break; 22045916cd2Sjpk } 22145916cd2Sjpk } 22245916cd2Sjpk 22345916cd2Sjpk return (status); 22445916cd2Sjpk } 22545916cd2Sjpk 22645916cd2Sjpk int 22745916cd2Sjpk print_da_defs(da_defs_t *da_defs) 22845916cd2Sjpk { 22945916cd2Sjpk char optbuf[BUFSIZ]; 23045916cd2Sjpk char *p = NULL; 23145916cd2Sjpk 23245916cd2Sjpk if (da_defs->devopts == NULL) { 23345916cd2Sjpk dprintf("No default attributes for %s\n", da_defs->devtype); 23445916cd2Sjpk return (DEFATTRSERR); 23545916cd2Sjpk } 23645916cd2Sjpk (void) printf("dev_type=%s\n", da_defs->devtype); 23745916cd2Sjpk if (_kva2str(da_defs->devopts, optbuf, sizeof (optbuf), KV_ASSIGN, 23845916cd2Sjpk KV_TOKEN_DELIMIT) == 0) { 23945916cd2Sjpk if (p = rindex(optbuf, ':')) 24045916cd2Sjpk *p = '\0'; 24145916cd2Sjpk (void) printf("\t%s\n", optbuf); 24245916cd2Sjpk } 24345916cd2Sjpk 2447c478bd9Sstevel@tonic-gate return (0); 2457c478bd9Sstevel@tonic-gate } 2467c478bd9Sstevel@tonic-gate 24745916cd2Sjpk void 24845916cd2Sjpk print_dev_attrs(int optflag, devalloc_t *da, devmap_t *dm, 24945916cd2Sjpk struct file_info *fip) 2507c478bd9Sstevel@tonic-gate { 25145916cd2Sjpk char *p = NULL; 25245916cd2Sjpk char optbuf[BUFSIZ]; 2537c478bd9Sstevel@tonic-gate 25445916cd2Sjpk (void) printf("device=%s%s", dm->dmap_devname, KV_DELIMITER); 25545916cd2Sjpk (void) printf("type=%s%s", dm->dmap_devtype, KV_DELIMITER); 25645916cd2Sjpk (void) printf("auths=%s%s", 25745916cd2Sjpk (da->da_devauth ? da->da_devauth : ""), KV_DELIMITER); 25845916cd2Sjpk (void) printf("clean=%s%s", 25945916cd2Sjpk (da->da_devexec ? da->da_devexec : ""), KV_DELIMITER); 26045916cd2Sjpk if (da->da_devopts != NULL) { 26145916cd2Sjpk if (_kva2str(da->da_devopts, optbuf, sizeof (optbuf), 26245916cd2Sjpk KV_ASSIGN, KV_TOKEN_DELIMIT) == 0) { 26345916cd2Sjpk if (p = rindex(optbuf, ':')) 26445916cd2Sjpk *p = '\0'; 26545916cd2Sjpk (void) printf("%s", optbuf); 26645916cd2Sjpk } 26745916cd2Sjpk } 26845916cd2Sjpk (void) printf("%s", KV_DELIMITER); 26945916cd2Sjpk if (optflag & WINDOWING) { 27010ddde3aSaj if ((fip->fi_message != NULL) && 27110ddde3aSaj (strcmp(fip->fi_message, DAOPT_CLASS) == 0)) 27210ddde3aSaj (void) printf("owner=/FREE%s", KV_DELIMITER); 27345916cd2Sjpk else if (DEV_ERRORED(fip->fi_stat)) 27445916cd2Sjpk (void) printf("owner=/ERROR%s", KV_DELIMITER); 27545916cd2Sjpk else if (!DEV_ALLOCATED(fip->fi_stat)) 27645916cd2Sjpk (void) printf("owner=/FREE%s", KV_DELIMITER); 27745916cd2Sjpk else 278f48205beScasper (void) printf("owner=%u%s", fip->fi_stat.st_uid, 27945916cd2Sjpk KV_DELIMITER); 28045916cd2Sjpk } 28145916cd2Sjpk (void) printf("files=%s", dm->dmap_devlist); 28245916cd2Sjpk (void) printf("\n"); 28345916cd2Sjpk } 28445916cd2Sjpk 28545916cd2Sjpk void 28645916cd2Sjpk print_dev(devmap_t *dm) 28745916cd2Sjpk { 28845916cd2Sjpk char **file; 28945916cd2Sjpk 29045916cd2Sjpk (void) printf(gettext("device: %s "), dm->dmap_devname); 29145916cd2Sjpk (void) printf(gettext("type: %s "), dm->dmap_devtype); 2927c478bd9Sstevel@tonic-gate (void) printf(gettext("files:")); 29345916cd2Sjpk file = dm->dmap_devarray; 29445916cd2Sjpk if (file != NULL) { 29545916cd2Sjpk for (; *file != NULL; file++) 29645916cd2Sjpk (void) printf(" %s", *file); 2977c478bd9Sstevel@tonic-gate } 2987c478bd9Sstevel@tonic-gate (void) printf("\n"); 2997c478bd9Sstevel@tonic-gate } 3007c478bd9Sstevel@tonic-gate 30145916cd2Sjpk /* ARGSUSED */ 30245916cd2Sjpk int 30345916cd2Sjpk _list_device(int optflag, uid_t uid, devalloc_t *da, char *zonename) 3047c478bd9Sstevel@tonic-gate { 30545916cd2Sjpk int bytes = 0; 30645916cd2Sjpk int error = 0; 30745916cd2Sjpk int is_authorized = 0; 30845916cd2Sjpk char *fname = NULL; 3097c478bd9Sstevel@tonic-gate char file_name[MAXPATHLEN]; 31045916cd2Sjpk devmap_t *dm; 31145916cd2Sjpk struct file_info fi; 31245916cd2Sjpk struct state_file sf; 3137c478bd9Sstevel@tonic-gate 31410ddde3aSaj fi.fi_message = NULL; 31545916cd2Sjpk setdmapent(); 31645916cd2Sjpk if ((dm = getdmapnam(da->da_devname)) == NULL) { 31745916cd2Sjpk enddmapent(); 31845916cd2Sjpk dprintf("Unable to find %s in the maps database\n", 31945916cd2Sjpk da->da_devname); 32045916cd2Sjpk return (NODMAPERR); 3217c478bd9Sstevel@tonic-gate } 32245916cd2Sjpk enddmapent(); 32310ddde3aSaj 32410ddde3aSaj if ((optflag & CLASS) && 32510ddde3aSaj (!(optflag & (LISTALL | LISTFREE | LISTALLOC)))) { 32610ddde3aSaj fi.fi_message = DAOPT_CLASS; 32710ddde3aSaj if (optflag & LISTATTRS) 32810ddde3aSaj print_dev_attrs(optflag, da, dm, &fi); 32910ddde3aSaj else 33010ddde3aSaj print_dev(dm); 33110ddde3aSaj goto out; 33210ddde3aSaj } 33310ddde3aSaj 33445916cd2Sjpk if (system_labeled) { 33545916cd2Sjpk if ((error = _dev_file_name(&sf, dm)) != 0) { 33645916cd2Sjpk freedmapent(dm); 33745916cd2Sjpk dprintf("Unable to find %s device files\n", 33845916cd2Sjpk da->da_devname); 33945916cd2Sjpk error = NODMAPERR; 34045916cd2Sjpk goto out; 3417c478bd9Sstevel@tonic-gate } 34245916cd2Sjpk fname = sf.sf_path; 34345916cd2Sjpk } else { 34445916cd2Sjpk bytes = snprintf(file_name, MAXPATHLEN, "%s/%s", DAC_DIR, 34545916cd2Sjpk da->da_devname); 34645916cd2Sjpk if (bytes <= 0) { 34745916cd2Sjpk error = DEVNAMEERR; 34845916cd2Sjpk goto out; 34945916cd2Sjpk } else if (bytes >= MAXPATHLEN) { 35045916cd2Sjpk dprintf("device name %s is too long.\n", 35145916cd2Sjpk da->da_devname); 35245916cd2Sjpk error = DEVLONGERR; 35345916cd2Sjpk goto out; 3547c478bd9Sstevel@tonic-gate } 35545916cd2Sjpk fname = file_name; 35645916cd2Sjpk } 35745916cd2Sjpk if (stat(fname, &fi.fi_stat) != 0) { 35845916cd2Sjpk dprintf("Unable to stat %s\n", fname); 3597c478bd9Sstevel@tonic-gate dperror("Error:"); 36045916cd2Sjpk error = DACACCERR; 36145916cd2Sjpk goto out; 36245916cd2Sjpk } 36345916cd2Sjpk is_authorized = _is_dev_authorized(da, uid); 36445916cd2Sjpk if (optflag & LISTFREE) { /* list_devices -n */ 36545916cd2Sjpk /* 36645916cd2Sjpk * list all free devices 36745916cd2Sjpk */ 36845916cd2Sjpk if (DEV_ALLOCATED(fi.fi_stat)) { 36945916cd2Sjpk error = PREALLOCERR; 37045916cd2Sjpk goto out; 37145916cd2Sjpk } 37245916cd2Sjpk if (system_labeled) { 37345916cd2Sjpk /* 37445916cd2Sjpk * for this free device, check if - 37545916cd2Sjpk * 1. user has authorization to allocate 37645916cd2Sjpk * 2. the zone label is within the label range of the 37745916cd2Sjpk * device 37845916cd2Sjpk */ 37945916cd2Sjpk if (is_authorized == ALLOC_BY_NONE) { 38045916cd2Sjpk error = DAUTHERR; 38145916cd2Sjpk goto out; 38245916cd2Sjpk } else if (is_authorized == 0) { 38345916cd2Sjpk error = UAUTHERR; 38445916cd2Sjpk goto out; 38545916cd2Sjpk } 38645916cd2Sjpk if (_check_label(da, zonename, uid, 38745916cd2Sjpk CHECK_DRANGE) != 0) { 38845916cd2Sjpk error = LABELRNGERR; 38945916cd2Sjpk goto out; 39045916cd2Sjpk } 39145916cd2Sjpk } 39245916cd2Sjpk } else if (optflag & LISTALLOC) { /* list_devices -u */ 39345916cd2Sjpk /* 39445916cd2Sjpk * list all allocated devices 39545916cd2Sjpk */ 39645916cd2Sjpk if (!DEV_ALLOCATED(fi.fi_stat)) { 39745916cd2Sjpk error = DEVNALLOCERR; 39845916cd2Sjpk goto out; 39945916cd2Sjpk } 40045916cd2Sjpk if (fi.fi_stat.st_uid != uid) { 40145916cd2Sjpk error = DEVSTATEERR; 40245916cd2Sjpk goto out; 40345916cd2Sjpk } 40445916cd2Sjpk if (system_labeled) { 40545916cd2Sjpk /* 40645916cd2Sjpk * check if the zone label equals the label at which 40745916cd2Sjpk * the device is allocated. 40845916cd2Sjpk */ 40945916cd2Sjpk if (_check_label(da, zonename, uid, 41045916cd2Sjpk CHECK_ZLABEL) != 0) { 41145916cd2Sjpk error = LABELRNGERR; 41245916cd2Sjpk goto out; 41345916cd2Sjpk } 41445916cd2Sjpk } 41545916cd2Sjpk } else if (optflag & LISTALL) { /* list_devices -l */ 41645916cd2Sjpk /* 41745916cd2Sjpk * list all devices - free and allocated - available 41845916cd2Sjpk */ 41945916cd2Sjpk if (DEV_ALLOCATED(fi.fi_stat)) { 42045916cd2Sjpk if (optflag & WINDOWING && 42145916cd2Sjpk (is_authorized == ALLOC_BY_NONE)) { 42245916cd2Sjpk /* 42345916cd2Sjpk * don't complain if we're here for the GUI. 42445916cd2Sjpk */ 42545916cd2Sjpk error = 0; 42645916cd2Sjpk } else if (fi.fi_stat.st_uid != uid) { 42745916cd2Sjpk if (!(optflag & WINDOWING)) { 42845916cd2Sjpk error = ALLOCUERR; 42945916cd2Sjpk goto out; 43045916cd2Sjpk } 43145916cd2Sjpk } 43245916cd2Sjpk if (system_labeled && !(optflag & WINDOWING)) { 43345916cd2Sjpk /* 43445916cd2Sjpk * if we're not displaying in the GUI, 43545916cd2Sjpk * check if the zone label equals the label 43645916cd2Sjpk * at which the device is allocated. 43745916cd2Sjpk */ 43845916cd2Sjpk if (_check_label(da, zonename, uid, 43945916cd2Sjpk CHECK_ZLABEL) != 0) { 44045916cd2Sjpk error = LABELRNGERR; 44145916cd2Sjpk goto out; 44245916cd2Sjpk } 44345916cd2Sjpk } 44445916cd2Sjpk } else if (system_labeled && !(optflag & WINDOWING)) { 44545916cd2Sjpk /* 44645916cd2Sjpk * if we're not displaying in the GUI, 44745916cd2Sjpk * for this free device, check if - 44845916cd2Sjpk * 1. user has authorization to allocate 44945916cd2Sjpk * 2. the zone label is within the label range of the 45045916cd2Sjpk * device 45145916cd2Sjpk */ 45245916cd2Sjpk if (is_authorized == ALLOC_BY_NONE) { 45345916cd2Sjpk error = DAUTHERR; 45445916cd2Sjpk goto out; 45545916cd2Sjpk } else if (is_authorized == 0) { 45645916cd2Sjpk error = UAUTHERR; 45745916cd2Sjpk goto out; 45845916cd2Sjpk } 45945916cd2Sjpk if (_check_label(da, zonename, uid, 46045916cd2Sjpk CHECK_DRANGE) != 0) { 46145916cd2Sjpk error = LABELRNGERR; 46245916cd2Sjpk goto out; 46345916cd2Sjpk } 46445916cd2Sjpk } 46545916cd2Sjpk } 46645916cd2Sjpk if (system_labeled && DEV_ERRORED(fi.fi_stat) && !(optflag & LISTALL)) { 46745916cd2Sjpk error = DEVSTATEERR; 46845916cd2Sjpk goto out; 46945916cd2Sjpk } 47045916cd2Sjpk if (check_devs(dm) == -1) { 47145916cd2Sjpk error = DSPMISSERR; 47245916cd2Sjpk goto out; 47345916cd2Sjpk } 47445916cd2Sjpk if (optflag & LISTATTRS) 47545916cd2Sjpk print_dev_attrs(optflag, da, dm, &fi); 47645916cd2Sjpk else 47745916cd2Sjpk print_dev(dm); 47845916cd2Sjpk 47945916cd2Sjpk error = 0; 48045916cd2Sjpk 48145916cd2Sjpk out: 48245916cd2Sjpk freedmapent(dm); 48345916cd2Sjpk return (error); 4847c478bd9Sstevel@tonic-gate } 4857c478bd9Sstevel@tonic-gate 48645916cd2Sjpk /* ARGSUSED */ 48745916cd2Sjpk int 48845916cd2Sjpk list_devices(int optflag, uid_t uid, char *device, char *zonename) 48945916cd2Sjpk { 49045916cd2Sjpk int error = 0; 49110ddde3aSaj char *class = NULL; 49245916cd2Sjpk da_defs_t *da_defs; 49345916cd2Sjpk devalloc_t *da; 4947c478bd9Sstevel@tonic-gate 49545916cd2Sjpk if (system_labeled && optflag & WINDOWING && !(optflag & LISTATTRS)) { 49645916cd2Sjpk /* 49745916cd2Sjpk * Private interface for GUI. 49845916cd2Sjpk */ 49945916cd2Sjpk (void) puts(DA_DB_LOCK); 5007c478bd9Sstevel@tonic-gate return (0); 5017c478bd9Sstevel@tonic-gate } 50245916cd2Sjpk if (optflag & USERID) { 50345916cd2Sjpk /* 50445916cd2Sjpk * we need device.revoke to list someone else's devices 50545916cd2Sjpk */ 50645916cd2Sjpk if (!_is_authorized(DEVICE_REVOKE_AUTH, getuid())) 50745916cd2Sjpk return (UAUTHERR); 50845916cd2Sjpk } 50945916cd2Sjpk if (system_labeled) { 51045916cd2Sjpk if (!(optflag & USERID) && 51145916cd2Sjpk !_is_authorized(DEFAULT_DEV_ALLOC_AUTH, uid)) 51245916cd2Sjpk /* 51345916cd2Sjpk * we need device.allocate to list our devices 51445916cd2Sjpk */ 51545916cd2Sjpk return (UAUTHERR); 51645916cd2Sjpk if (optflag & LISTDEFS) { 51745916cd2Sjpk /* 51845916cd2Sjpk * list default attrs from devalloc_defaults 51945916cd2Sjpk */ 52045916cd2Sjpk setdadefent(); 52145916cd2Sjpk if (device) { 52245916cd2Sjpk /* 52345916cd2Sjpk * list default attrs for this device type 52445916cd2Sjpk */ 52545916cd2Sjpk da_defs = getdadeftype(device); 52645916cd2Sjpk if (da_defs == NULL) { 52745916cd2Sjpk enddadefent(); 52845916cd2Sjpk dprintf("No default attributes for " 52945916cd2Sjpk "%s\n", device); 53045916cd2Sjpk return (DEFATTRSERR); 53145916cd2Sjpk } 53245916cd2Sjpk error = print_da_defs(da_defs); 53345916cd2Sjpk freedadefent(da_defs); 53445916cd2Sjpk } else { 53545916cd2Sjpk /* 53645916cd2Sjpk * list everything in devalloc_defaults 53745916cd2Sjpk */ 53845916cd2Sjpk while ((da_defs = getdadefent()) != NULL) { 53945916cd2Sjpk (void) print_da_defs(da_defs); 54045916cd2Sjpk freedadefent(da_defs); 54145916cd2Sjpk } 54245916cd2Sjpk } 54345916cd2Sjpk enddadefent(); 54445916cd2Sjpk return (error); 54545916cd2Sjpk } 5467c478bd9Sstevel@tonic-gate } 54710ddde3aSaj /* 54810ddde3aSaj * Lock the database to make sure no body writes to it while we are 54910ddde3aSaj * reading. 55010ddde3aSaj */ 55110ddde3aSaj (void) lock_dev(NULL, NULL); 5527c478bd9Sstevel@tonic-gate setdaent(); 5537c478bd9Sstevel@tonic-gate if (device) { 55410ddde3aSaj if (optflag & CLASS) { 55510ddde3aSaj /* 55610ddde3aSaj * list all devices of this class. 55710ddde3aSaj */ 55810ddde3aSaj while ((da = getdaent()) != NULL) { 55910ddde3aSaj class = kva_match(da->da_devopts, DAOPT_CLASS); 56010ddde3aSaj if (class && (strcmp(class, device) == 0)) { 56110ddde3aSaj (void) _list_device(optflag, uid, da, 56210ddde3aSaj zonename); 56310ddde3aSaj } 56410ddde3aSaj freedaent(da); 56510ddde3aSaj } 56610ddde3aSaj } else { 56745916cd2Sjpk /* 56845916cd2Sjpk * list this device 56945916cd2Sjpk */ 57045916cd2Sjpk if ((da = getdanam(device)) == NULL) { 5717c478bd9Sstevel@tonic-gate enddaent(); 57245916cd2Sjpk return (NODAERR); 57345916cd2Sjpk } 57445916cd2Sjpk error = _list_device(optflag, uid, da, zonename); 57545916cd2Sjpk freedaent(da); 57610ddde3aSaj } 57745916cd2Sjpk } else { 57845916cd2Sjpk /* 57945916cd2Sjpk * list all devices 58045916cd2Sjpk */ 58145916cd2Sjpk while ((da = getdaent()) != NULL) { 58245916cd2Sjpk (void) _list_device(optflag, uid, da, zonename); 58345916cd2Sjpk freedaent(da); 58445916cd2Sjpk } 58545916cd2Sjpk } 58645916cd2Sjpk enddaent(); 58745916cd2Sjpk 58845916cd2Sjpk return (error); 5897c478bd9Sstevel@tonic-gate } 5907c478bd9Sstevel@tonic-gate 5917c478bd9Sstevel@tonic-gate /* 5927c478bd9Sstevel@tonic-gate * Set the DAC characteristics of the file. 5937c478bd9Sstevel@tonic-gate * This uses a fancy chmod() by setting a minimal ACL which sets the mode 5947c478bd9Sstevel@tonic-gate * and discards any existing ACL. 5957c478bd9Sstevel@tonic-gate */ 59645916cd2Sjpk int 59745916cd2Sjpk _newdac(char *file, uid_t owner, gid_t group, o_mode_t mode) 5987c478bd9Sstevel@tonic-gate { 5997c478bd9Sstevel@tonic-gate int err = 0; 6007c478bd9Sstevel@tonic-gate 60145916cd2Sjpk if (mode == ALLOC_MODE) { 6027c478bd9Sstevel@tonic-gate if (chown(file, owner, group) == -1) { 60345916cd2Sjpk dperror("newdac: unable to chown"); 60445916cd2Sjpk err = CHOWNERR; 60545916cd2Sjpk } 60645916cd2Sjpk } else do { 60745916cd2Sjpk if (chown(file, owner, group) == -1) { 60845916cd2Sjpk dperror("newdac: unable to chown"); 60945916cd2Sjpk err = CHOWNERR; 6107c478bd9Sstevel@tonic-gate } 6117c478bd9Sstevel@tonic-gate } while (fdetach(file) == 0); 6127c478bd9Sstevel@tonic-gate 61345916cd2Sjpk if (err) 61445916cd2Sjpk return (err); 61545916cd2Sjpk 61645916cd2Sjpk if (strncmp(file, "/dev/", strlen("/dev/")) != 0) { 61745916cd2Sjpk /* 61845916cd2Sjpk * This could be a SunRay device that is in /tmp. 61945916cd2Sjpk */ 62045916cd2Sjpk if (chmod(file, mode) == -1) { 62145916cd2Sjpk dperror("newdac: unable to chmod"); 62245916cd2Sjpk err = SETACLERR; 62345916cd2Sjpk } 62445916cd2Sjpk } else { 625fa9e4066Sahrens err = acl_strip(file, owner, group, (mode_t)mode); 62645916cd2Sjpk } 627fa9e4066Sahrens 628fa9e4066Sahrens if (err != 0) { 62945916cd2Sjpk dperror("newdac: unable to setacl"); 63045916cd2Sjpk err = SETACLERR; 6317c478bd9Sstevel@tonic-gate } 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate return (err); 6347c478bd9Sstevel@tonic-gate } 6357c478bd9Sstevel@tonic-gate 63610ddde3aSaj /* 63710ddde3aSaj * lock_dev - 63810ddde3aSaj * locks a section of DA_DB_LOCK. 63910ddde3aSaj * returns lock fd if successful, else -1 on error. 64010ddde3aSaj */ 6417c478bd9Sstevel@tonic-gate static int 64210ddde3aSaj lock_dev(char *file, struct stat *statbuf) 6437c478bd9Sstevel@tonic-gate { 64410ddde3aSaj static int lockfd = -1; 64510ddde3aSaj int ret; 64610ddde3aSaj int count = 0; 64710ddde3aSaj int retry = 10; 64810ddde3aSaj off_t size = 0; 64910ddde3aSaj off_t offset; 65010ddde3aSaj char *lockfile; 6517c478bd9Sstevel@tonic-gate 65210ddde3aSaj if (system_labeled) 65310ddde3aSaj lockfile = DA_DB_LOCK; 65410ddde3aSaj else 65510ddde3aSaj lockfile = file; 65610ddde3aSaj 65710ddde3aSaj if (statbuf) { 65810ddde3aSaj offset = statbuf->st_rdev; 6597c478bd9Sstevel@tonic-gate dprintf("locking %s\n", file); 66010ddde3aSaj } else { 66110ddde3aSaj offset = 0; 66210ddde3aSaj dprintf("locking %s\n", lockfile); 6637c478bd9Sstevel@tonic-gate } 66410ddde3aSaj if ((lockfd == -1) && 66510ddde3aSaj (lockfd = open(lockfile, O_RDWR | O_CREAT, 0600)) == -1) { 66610ddde3aSaj dperror("lock_dev: cannot open lock file"); 66710ddde3aSaj return (-1); 66810ddde3aSaj } 66910ddde3aSaj if (system_labeled) { 67010ddde3aSaj (void) _newdac(lockfile, DA_UID, DA_GID, 0600); 67110ddde3aSaj if (lseek(lockfd, offset, SEEK_SET) == -1) { 67210ddde3aSaj dperror("lock_dev: cannot position lock file"); 67310ddde3aSaj return (-1); 67410ddde3aSaj } 67510ddde3aSaj size = 1; 67610ddde3aSaj } 67710ddde3aSaj errno = 0; 67810ddde3aSaj while (retry) { 67910ddde3aSaj count++; 68010ddde3aSaj ret = lockf(lockfd, F_TLOCK, size); 68110ddde3aSaj if (ret == 0) 68210ddde3aSaj return (lockfd); 68310ddde3aSaj if ((errno != EACCES) && (errno != EAGAIN)) { 68445916cd2Sjpk dperror("lock_dev: cannot set lock"); 68510ddde3aSaj return (-1); 68610ddde3aSaj } 68710ddde3aSaj retry--; 68810ddde3aSaj (void) sleep(count); 68910ddde3aSaj errno = 0; 6907c478bd9Sstevel@tonic-gate } 6917c478bd9Sstevel@tonic-gate 69210ddde3aSaj return (-1); 6937c478bd9Sstevel@tonic-gate } 6947c478bd9Sstevel@tonic-gate 69545916cd2Sjpk int 69645916cd2Sjpk mk_alloc(devmap_t *list, uid_t uid, struct zone_path *zpath) 6977c478bd9Sstevel@tonic-gate { 69845916cd2Sjpk int i; 69945916cd2Sjpk int error = 0; 70045916cd2Sjpk char **file; 70145916cd2Sjpk gid_t gid = getgid(); 70245916cd2Sjpk mode_t mode = ALLOC_MODE; 7037c478bd9Sstevel@tonic-gate 70445916cd2Sjpk file = list->dmap_devarray; 70545916cd2Sjpk if (file == NULL) 70645916cd2Sjpk return (NODMAPERR); 70745916cd2Sjpk for (; *file != NULL; file++) { 70845916cd2Sjpk dprintf("Allocating %s\n", *file); 70945916cd2Sjpk if ((error = _newdac(*file, uid, gid, mode)) != 0) { 71010ddde3aSaj (void) _newdac(*file, ALLOC_ERRID, DA_GID, 7117c478bd9Sstevel@tonic-gate ALLOC_ERR_MODE); 71245916cd2Sjpk break; 71345916cd2Sjpk } 71445916cd2Sjpk } 71545916cd2Sjpk if (system_labeled && zpath->count && (error == 0)) { 71645916cd2Sjpk /* 71745916cd2Sjpk * mark as allocated any new device nodes that we 71845916cd2Sjpk * created in local zone 71945916cd2Sjpk */ 72045916cd2Sjpk for (i = 0; i < zpath->count; i++) { 72145916cd2Sjpk dprintf("Allocating %s\n", zpath->path[i]); 72245916cd2Sjpk if ((error = _newdac(zpath->path[i], uid, gid, 72345916cd2Sjpk mode)) != 0) { 72445916cd2Sjpk (void) _newdac(zpath->path[i], ALLOC_ERRID, 72510ddde3aSaj DA_GID, ALLOC_ERR_MODE); 72645916cd2Sjpk break; 72745916cd2Sjpk } 72845916cd2Sjpk } 7297c478bd9Sstevel@tonic-gate } 7307c478bd9Sstevel@tonic-gate 73145916cd2Sjpk return (error); 7327c478bd9Sstevel@tonic-gate } 7337c478bd9Sstevel@tonic-gate 7347c478bd9Sstevel@tonic-gate /* 7357c478bd9Sstevel@tonic-gate * mk_revoke() is used instead of system("/usr/sbin/fuser -k file") 7367c478bd9Sstevel@tonic-gate * because "/usr/sbin/fuser -k file" kills all processes 7377c478bd9Sstevel@tonic-gate * working with the file, even "vold" (bug #4095152). 7387c478bd9Sstevel@tonic-gate */ 73945916cd2Sjpk int 74045916cd2Sjpk mk_revoke(int optflag, char *file) 7417c478bd9Sstevel@tonic-gate { 7427c478bd9Sstevel@tonic-gate int r = 0, p[2], fp, lock; 74345916cd2Sjpk int fuserpid; 74445916cd2Sjpk char buf[MAXPATHLEN]; 7457c478bd9Sstevel@tonic-gate FILE *ptr; 74645916cd2Sjpk pid_t c_pid; 7477c478bd9Sstevel@tonic-gate prpsinfo_t info; 7487c478bd9Sstevel@tonic-gate 7497c478bd9Sstevel@tonic-gate (void) strcpy(buf, PROCFS); 7507c478bd9Sstevel@tonic-gate /* 75145916cd2Sjpk * vfork() and execl() just to make the same output 7527c478bd9Sstevel@tonic-gate * as before fixing of bug #4095152. 7537c478bd9Sstevel@tonic-gate * The problem is that the "fuser" command prints 7547c478bd9Sstevel@tonic-gate * one part of output into stderr and another into stdout, 7557c478bd9Sstevel@tonic-gate * but user sees them mixed. Of course, better to change "fuser" 7567c478bd9Sstevel@tonic-gate * or to intercept and not to print its output. 7577c478bd9Sstevel@tonic-gate */ 75845916cd2Sjpk if (!(optflag & SILENT)) { 7597c478bd9Sstevel@tonic-gate c_pid = vfork(); 7607c478bd9Sstevel@tonic-gate if (c_pid == -1) 7617c478bd9Sstevel@tonic-gate return (-1); 7627c478bd9Sstevel@tonic-gate if (c_pid == 0) { 7637c478bd9Sstevel@tonic-gate dprintf("first exec fuser %s\n", file); 76445916cd2Sjpk (void) execl("/usr/sbin/fuser", "fuser", file, NULL); 7657c478bd9Sstevel@tonic-gate dperror("first exec fuser"); 7667c478bd9Sstevel@tonic-gate _exit(1); 7677c478bd9Sstevel@tonic-gate } 7687c478bd9Sstevel@tonic-gate 7697c478bd9Sstevel@tonic-gate (void) waitpid(c_pid, &lock, 0); 7707c478bd9Sstevel@tonic-gate dprintf("exit status %x\n", lock); 7717c478bd9Sstevel@tonic-gate if (WEXITSTATUS(lock) != 0) 7727c478bd9Sstevel@tonic-gate return (-1); 7737c478bd9Sstevel@tonic-gate } 77445916cd2Sjpk dprintf("first continuing c_pid=%d\n", (int)c_pid); 7757c478bd9Sstevel@tonic-gate if (pipe(p)) { 7767c478bd9Sstevel@tonic-gate dperror("pipe"); 7777c478bd9Sstevel@tonic-gate return (-1); 7787c478bd9Sstevel@tonic-gate } 77945916cd2Sjpk /* vfork() and execl() to catch output and to process it */ 7807c478bd9Sstevel@tonic-gate c_pid = vfork(); 7817c478bd9Sstevel@tonic-gate if (c_pid == -1) { 7827c478bd9Sstevel@tonic-gate dperror("second vfork"); 7837c478bd9Sstevel@tonic-gate return (-1); 7847c478bd9Sstevel@tonic-gate } 78545916cd2Sjpk dprintf("second continuing c_pid=%d\n", (int)c_pid); 7867c478bd9Sstevel@tonic-gate if (c_pid == 0) { 7877c478bd9Sstevel@tonic-gate (void) close(p[0]); 7887c478bd9Sstevel@tonic-gate (void) close(1); 7897c478bd9Sstevel@tonic-gate (void) fcntl(p[1], F_DUPFD, 1); 7907c478bd9Sstevel@tonic-gate (void) close(p[1]); 7917c478bd9Sstevel@tonic-gate (void) close(2); 7927c478bd9Sstevel@tonic-gate dprintf("second exec fuser %s\n", file); 79345916cd2Sjpk (void) execl("/usr/sbin/fuser", "fuser", file, NULL); 7947c478bd9Sstevel@tonic-gate dperror("second exec fuser"); 7957c478bd9Sstevel@tonic-gate _exit(1); 7967c478bd9Sstevel@tonic-gate } 7977c478bd9Sstevel@tonic-gate (void) close(p[1]); 7987c478bd9Sstevel@tonic-gate if ((ptr = fdopen(p[0], "r")) != NULL) { 7997c478bd9Sstevel@tonic-gate while (!feof(ptr)) { 80045916cd2Sjpk if (fscanf(ptr, "%d", &fuserpid) > 0) { 80145916cd2Sjpk (void) sprintf(buf + strlen(PROCFS), "%d", 80245916cd2Sjpk fuserpid); 8037c478bd9Sstevel@tonic-gate if ((fp = open(buf, O_RDONLY)) == -1) { 8047c478bd9Sstevel@tonic-gate dperror(buf); 8057c478bd9Sstevel@tonic-gate continue; 8067c478bd9Sstevel@tonic-gate } 80745916cd2Sjpk if (ioctl(fp, PIOCPSINFO, 80845916cd2Sjpk (char *)&info) == -1) { 80945916cd2Sjpk dprintf("%d psinfo failed", fuserpid); 8107c478bd9Sstevel@tonic-gate dperror(""); 8117c478bd9Sstevel@tonic-gate (void) close(fp); 8127c478bd9Sstevel@tonic-gate continue; 8137c478bd9Sstevel@tonic-gate } 8147c478bd9Sstevel@tonic-gate (void) close(fp); 8157c478bd9Sstevel@tonic-gate if (strcmp(info.pr_fname, "vold") == NULL) { 81645916cd2Sjpk dprintf("%d matched vold name\n", 81745916cd2Sjpk fuserpid); 8187c478bd9Sstevel@tonic-gate continue; 8197c478bd9Sstevel@tonic-gate } 820*7248adcbSJan Parcel if (strcmp(info.pr_fname, "deallocate") 821*7248adcbSJan Parcel == NULL) { 822*7248adcbSJan Parcel dprintf("%d matched deallocate name\n", 823*7248adcbSJan Parcel fuserpid); 824*7248adcbSJan Parcel continue; 825*7248adcbSJan Parcel } 8267c478bd9Sstevel@tonic-gate dprintf("killing %s", info.pr_fname); 82745916cd2Sjpk dprintf("(%d)\n", fuserpid); 82845916cd2Sjpk if ((r = 82945916cd2Sjpk kill((pid_t)fuserpid, SIGKILL)) == -1) { 83045916cd2Sjpk dprintf("kill %d", fuserpid); 8317c478bd9Sstevel@tonic-gate dperror(""); 8327c478bd9Sstevel@tonic-gate break; 8337c478bd9Sstevel@tonic-gate } 8347c478bd9Sstevel@tonic-gate } 8357c478bd9Sstevel@tonic-gate } 8367c478bd9Sstevel@tonic-gate } else { 83745916cd2Sjpk dperror("fdopen(p[0], r)"); 8387c478bd9Sstevel@tonic-gate r = -1; 8397c478bd9Sstevel@tonic-gate } 8407c478bd9Sstevel@tonic-gate (void) fclose(ptr); 84145916cd2Sjpk 8427c478bd9Sstevel@tonic-gate return (r); 8437c478bd9Sstevel@tonic-gate } 8447c478bd9Sstevel@tonic-gate 84545916cd2Sjpk int 84645916cd2Sjpk mk_unalloc(int optflag, devmap_t *list) 8477c478bd9Sstevel@tonic-gate { 8487c478bd9Sstevel@tonic-gate int error = 0; 8497c478bd9Sstevel@tonic-gate int status; 85045916cd2Sjpk char **file; 8517c478bd9Sstevel@tonic-gate 85245916cd2Sjpk audit_allocate_list(list->dmap_devlist); 85345916cd2Sjpk file = list->dmap_devarray; 85445916cd2Sjpk if (file == NULL) 85545916cd2Sjpk return (NODMAPERR); 85645916cd2Sjpk for (; *file != NULL; file++) { 85745916cd2Sjpk dprintf("Deallocating %s\n", *file); 85845916cd2Sjpk if (mk_revoke(optflag, *file) < 0) { 85945916cd2Sjpk dprintf("mk_unalloc: unable to revoke %s\n", *file); 86045916cd2Sjpk dperror(""); 86145916cd2Sjpk error = CNTFRCERR; 86245916cd2Sjpk } 86310ddde3aSaj status = _newdac(*file, DA_UID, DA_GID, DEALLOC_MODE); 86445916cd2Sjpk if (error == 0) 86545916cd2Sjpk error = status; 86645916cd2Sjpk 86745916cd2Sjpk } 86845916cd2Sjpk 86945916cd2Sjpk return (error); 87045916cd2Sjpk } 87145916cd2Sjpk 87245916cd2Sjpk int 87345916cd2Sjpk mk_error(devmap_t *list) 87445916cd2Sjpk { 87545916cd2Sjpk int status = 0; 87645916cd2Sjpk char **file; 87745916cd2Sjpk 87845916cd2Sjpk audit_allocate_list(list->dmap_devlist); 87945916cd2Sjpk file = list->dmap_devarray; 88045916cd2Sjpk if (file == NULL) 88145916cd2Sjpk return (NODMAPERR); 88245916cd2Sjpk for (; *file != NULL; file++) { 88345916cd2Sjpk dprintf("Putting %s in error state\n", *file); 88410ddde3aSaj status = _newdac(*file, ALLOC_ERRID, DA_GID, ALLOC_ERR_MODE); 88545916cd2Sjpk } 88645916cd2Sjpk 88745916cd2Sjpk return (status); 88845916cd2Sjpk } 88945916cd2Sjpk 89045916cd2Sjpk int 89145916cd2Sjpk exec_clean(int optflag, char *devname, char *path, uid_t uid, char *zonename, 89245916cd2Sjpk char *clean_arg) 89345916cd2Sjpk { 89445916cd2Sjpk int c; 89545916cd2Sjpk int status = 0, exit_status; 89645916cd2Sjpk char *mode, *cmd, *wdwcmd, *zoneroot; 89745916cd2Sjpk char *devzone = zonename; 89845916cd2Sjpk char wdwpath[PATH_MAX]; 89945916cd2Sjpk char zonepath[MAXPATHLEN]; 90045916cd2Sjpk char title[100]; 90145916cd2Sjpk char pw_buf[NSS_BUFLEN_PASSWD]; 90245916cd2Sjpk struct passwd pw_ent; 90345916cd2Sjpk 90445916cd2Sjpk zonepath[0] = '\0'; 90545916cd2Sjpk if (system_labeled) { 90645916cd2Sjpk if ((zoneroot = getzonerootbyname(zonename)) == NULL) { 90745916cd2Sjpk if (strcmp(clean_arg, ALLOC_CLEAN) == 0) { 90845916cd2Sjpk return (-1); 90945916cd2Sjpk } else if (optflag & FORCE) { 91045916cd2Sjpk (void) strcpy(zonepath, "/"); 91145916cd2Sjpk devzone = GLOBAL_ZONENAME; 91245916cd2Sjpk } else { 91345916cd2Sjpk dprintf("unable to get label for %s zone\n", 91445916cd2Sjpk zonename); 91545916cd2Sjpk return (-1); 91645916cd2Sjpk } 91745916cd2Sjpk } else { 91845916cd2Sjpk (void) strcpy(zonepath, zoneroot); 91945916cd2Sjpk free(zoneroot); 92045916cd2Sjpk } 92145916cd2Sjpk } 92245916cd2Sjpk if (getpwuid_r(uid, &pw_ent, pw_buf, sizeof (pw_buf)) == NULL) 92345916cd2Sjpk return (-1); 92445916cd2Sjpk if (optflag & FORCE_ALL) 9257c478bd9Sstevel@tonic-gate mode = "-I"; 92645916cd2Sjpk else if (optflag & FORCE) 9277c478bd9Sstevel@tonic-gate mode = "-f"; 9287c478bd9Sstevel@tonic-gate else 9297c478bd9Sstevel@tonic-gate mode = "-s"; 93045916cd2Sjpk if (path == NULL) 93145916cd2Sjpk return (0); 9327c478bd9Sstevel@tonic-gate if ((cmd = strrchr(path, '/')) == NULL) 9337c478bd9Sstevel@tonic-gate cmd = path; 9347c478bd9Sstevel@tonic-gate else 9357c478bd9Sstevel@tonic-gate cmd++; /* skip leading '/' */ 9367c478bd9Sstevel@tonic-gate c = vfork(); 9377c478bd9Sstevel@tonic-gate switch (c) { 9387c478bd9Sstevel@tonic-gate case -1: 9397c478bd9Sstevel@tonic-gate return (-1); 9407c478bd9Sstevel@tonic-gate case 0: 9417c478bd9Sstevel@tonic-gate (void) setuid(0); 94245916cd2Sjpk if (system_labeled && (optflag & WINDOWING)) { 94345916cd2Sjpk /* First try .windowing version of script */ 94445916cd2Sjpk (void) strncpy(wdwpath, path, PATH_MAX); 94545916cd2Sjpk (void) strncat(wdwpath, ".windowing", PATH_MAX); 94645916cd2Sjpk if ((wdwcmd = strrchr(wdwpath, '/')) == NULL) 94745916cd2Sjpk wdwcmd = wdwpath; 94845916cd2Sjpk (void) execl(wdwpath, wdwcmd, mode, devname, clean_arg, 94945916cd2Sjpk pw_ent.pw_name, devzone, zonepath, NULL); 95045916cd2Sjpk /* If that failed, run regular version via dtterm */ 95145916cd2Sjpk (void) snprintf(title, sizeof (title), 95245916cd2Sjpk "Device %s for %s", 95345916cd2Sjpk strcmp(clean_arg, ALLOC_CLEAN) == 0 ? 95445916cd2Sjpk "allocation" : "deallocation", devname); 95545916cd2Sjpk (void) execl("/usr/dt/bin/dtterm", "dtterm", 95645916cd2Sjpk "-title", title, "-geometry", "x10+100+400", 95745916cd2Sjpk "-e", "/etc/security/lib/wdwwrapper", 95845916cd2Sjpk path, mode, devname, clean_arg, pw_ent.pw_name, 95945916cd2Sjpk devzone, zonepath, NULL); 96045916cd2Sjpk /* 96145916cd2Sjpk * And if that failed, continue on to try 96245916cd2Sjpk * running regular version directly. 96345916cd2Sjpk */ 96445916cd2Sjpk } 9657c478bd9Sstevel@tonic-gate dprintf("clean script: %s, ", path); 9667c478bd9Sstevel@tonic-gate dprintf("cmd=%s, ", cmd); 9677c478bd9Sstevel@tonic-gate dprintf("mode=%s, ", mode); 96845916cd2Sjpk if (system_labeled) { 96945916cd2Sjpk dprintf("devname=%s ", devname); 97045916cd2Sjpk dprintf("zonename=%s ", devzone); 97145916cd2Sjpk dprintf("zonepath=%s ", zonepath); 97245916cd2Sjpk dprintf("username=%s\n", pw_ent.pw_name); 97345916cd2Sjpk (void) execl(path, cmd, mode, devname, clean_arg, 97445916cd2Sjpk pw_ent.pw_name, devzone, zonepath, NULL); 97545916cd2Sjpk } else { 97645916cd2Sjpk dprintf("devname=%s\n", devname); 97745916cd2Sjpk (void) execle(path, cmd, mode, devname, NULL, newenv); 97845916cd2Sjpk } 9797c478bd9Sstevel@tonic-gate dprintf("Unable to execute clean up script %s\n", path); 9807c478bd9Sstevel@tonic-gate dperror(""); 98145916cd2Sjpk exit(CNTDEXECERR); 9827c478bd9Sstevel@tonic-gate default: 98345916cd2Sjpk (void) waitpid(c, &status, 0); 98445916cd2Sjpk dprintf("Child %d", c); 98545916cd2Sjpk if (WIFEXITED(status)) { 98645916cd2Sjpk exit_status = WEXITSTATUS(status); 98745916cd2Sjpk dprintf(" exited, status: %d\n", exit_status); 98845916cd2Sjpk return (exit_status); 98945916cd2Sjpk } else if (WIFSIGNALED(status)) { 99045916cd2Sjpk dprintf(" killed, signal %d\n", WTERMSIG(status)); 99145916cd2Sjpk } else { 99245916cd2Sjpk dprintf(": exit status %d\n", status); 99345916cd2Sjpk } 9947c478bd9Sstevel@tonic-gate return (-1); 9957c478bd9Sstevel@tonic-gate } 9967c478bd9Sstevel@tonic-gate } 9977c478bd9Sstevel@tonic-gate 99845916cd2Sjpk int 99945916cd2Sjpk _deallocate_dev(int optflag, devalloc_t *da, devmap_t *dm_in, uid_t uid, 100010ddde3aSaj char *zonename, int *lock_fd) 10017c478bd9Sstevel@tonic-gate { 100245916cd2Sjpk int bytes = 0; 10037c478bd9Sstevel@tonic-gate int error = 0; 100445916cd2Sjpk int is_authorized = 0; 100545916cd2Sjpk uid_t nuid; 100645916cd2Sjpk char *fname = NULL; 100745916cd2Sjpk char file_name[MAXPATHLEN]; 100845916cd2Sjpk char *devzone = NULL; 100945916cd2Sjpk devmap_t *dm = NULL, *dm_new = NULL; 101045916cd2Sjpk struct stat stat_buf; 101145916cd2Sjpk struct state_file sf; 10127c478bd9Sstevel@tonic-gate 101345916cd2Sjpk if (dm_in == NULL) { 101445916cd2Sjpk setdmapent(); 101545916cd2Sjpk if ((dm_new = getdmapnam(da->da_devname)) == NULL) { 101645916cd2Sjpk enddmapent(); 101745916cd2Sjpk dprintf("Unable to find %s in device map database\n", 101845916cd2Sjpk da->da_devname); 101945916cd2Sjpk return (NODMAPERR); 102045916cd2Sjpk } 102145916cd2Sjpk enddmapent(); 102245916cd2Sjpk dm = dm_new; 102345916cd2Sjpk } else { 102445916cd2Sjpk dm = dm_in; 102545916cd2Sjpk } 102645916cd2Sjpk if (system_labeled) { 102745916cd2Sjpk if (_dev_file_name(&sf, dm) != 0) { 102845916cd2Sjpk if (dm_new) 102945916cd2Sjpk freedmapent(dm_new); 103045916cd2Sjpk dprintf("Unable to find %s device files\n", 103145916cd2Sjpk da->da_devname); 103245916cd2Sjpk error = NODMAPERR; 103345916cd2Sjpk goto out; 103445916cd2Sjpk } 103545916cd2Sjpk fname = sf.sf_path; 103645916cd2Sjpk } else { 103745916cd2Sjpk bytes = snprintf(file_name, MAXPATHLEN, "%s/%s", DAC_DIR, 103845916cd2Sjpk da->da_devname); 103945916cd2Sjpk if (bytes <= 0) { 104045916cd2Sjpk error = DEVNAMEERR; 104145916cd2Sjpk goto out; 104245916cd2Sjpk } else if (bytes >= MAXPATHLEN) { 104345916cd2Sjpk dprintf("device name %s is too long.\n", 104445916cd2Sjpk da->da_devname); 104545916cd2Sjpk error = DEVLONGERR; 104645916cd2Sjpk goto out; 104745916cd2Sjpk } 104845916cd2Sjpk fname = file_name; 10497c478bd9Sstevel@tonic-gate } 10507c478bd9Sstevel@tonic-gate 105145916cd2Sjpk audit_allocate_device(fname); 10527c478bd9Sstevel@tonic-gate 105345916cd2Sjpk if (stat(fname, &stat_buf) != 0) { 105445916cd2Sjpk dprintf("Unable to stat %s\n", fname); 105545916cd2Sjpk error = DACACCERR; 105645916cd2Sjpk goto out; 105745916cd2Sjpk } 105845916cd2Sjpk is_authorized = _is_dev_authorized(da, uid); 1059*7248adcbSJan Parcel if (is_authorized == ALLOC_BY_NONE) { 1060*7248adcbSJan Parcel dprintf("Not deallocating %s, not allocatable\n", 1061*7248adcbSJan Parcel da->da_devname); 1062*7248adcbSJan Parcel goto out; 1063*7248adcbSJan Parcel } 106445916cd2Sjpk if (!(optflag & (FORCE | FORCE_ALL)) && !is_authorized) { 106545916cd2Sjpk dprintf("User %d is unauthorized to deallocate\n", (int)uid); 106645916cd2Sjpk error = UAUTHERR; 106745916cd2Sjpk goto out; 106845916cd2Sjpk } 106945916cd2Sjpk if (system_labeled) { 107045916cd2Sjpk /* 107145916cd2Sjpk * unless we're here to deallocate by force, check if the 107245916cd2Sjpk * label at which the device is currently allocated is 107345916cd2Sjpk * within the user label range. 107445916cd2Sjpk */ 107545916cd2Sjpk if (!(optflag & FORCE) && 107645916cd2Sjpk _check_label(da, zonename, uid, CHECK_URANGE) != 0) { 107745916cd2Sjpk error = LABELRNGERR; 107845916cd2Sjpk goto out; 107945916cd2Sjpk } 108045916cd2Sjpk } 108145916cd2Sjpk if (!(optflag & FORCE) && stat_buf.st_uid != uid && 108245916cd2Sjpk DEV_ALLOCATED(stat_buf)) { 108345916cd2Sjpk error = ALLOCUERR; 108445916cd2Sjpk goto out; 108545916cd2Sjpk } 108645916cd2Sjpk if (!DEV_ALLOCATED(stat_buf)) { 108745916cd2Sjpk if (DEV_ERRORED(stat_buf)) { 108845916cd2Sjpk if (!(optflag & FORCE)) { 108945916cd2Sjpk error = DEVSTATEERR; 109045916cd2Sjpk goto out; 109145916cd2Sjpk } 109245916cd2Sjpk } else { 109345916cd2Sjpk error = DEVNALLOCERR; 109445916cd2Sjpk goto out; 109545916cd2Sjpk } 109645916cd2Sjpk } 109745916cd2Sjpk /* All checks passed, time to lock and deallocate */ 109810ddde3aSaj if ((*lock_fd = lock_dev(fname, &stat_buf)) == -1) { 109910ddde3aSaj error = DEVLKERR; 110045916cd2Sjpk goto out; 110110ddde3aSaj } 110245916cd2Sjpk if (system_labeled) { 110345916cd2Sjpk devzone = kva_match(da->da_devopts, DAOPT_ZONE); 110410ddde3aSaj if (devzone == NULL) { 110510ddde3aSaj devzone = GLOBAL_ZONENAME; 110610ddde3aSaj } else if (strcmp(devzone, GLOBAL_ZONENAME) != 0) { 110745916cd2Sjpk if ((remove_znode(devzone, dm) != 0) && 110845916cd2Sjpk !(optflag & FORCE)) { 110945916cd2Sjpk error = ZONEERR; 111045916cd2Sjpk goto out; 111145916cd2Sjpk } 111245916cd2Sjpk } 111345916cd2Sjpk } 111445916cd2Sjpk if ((error = mk_unalloc(optflag, dm)) != 0) { 111545916cd2Sjpk if (!(optflag & FORCE)) 111645916cd2Sjpk goto out; 111745916cd2Sjpk } 111845916cd2Sjpk if (system_labeled == 0) { 111910ddde3aSaj if ((error = _newdac(fname, DA_UID, DA_GID, 112045916cd2Sjpk DEALLOC_MODE)) != 0) { 112110ddde3aSaj (void) _newdac(file_name, DA_UID, DA_GID, 112245916cd2Sjpk ALLOC_ERR_MODE); 112345916cd2Sjpk goto out; 112445916cd2Sjpk } 112545916cd2Sjpk } 112645916cd2Sjpk /* 112745916cd2Sjpk * if we are deallocating device owned by someone else, 112845916cd2Sjpk * pass the owner's uid to the cleaning script. 112945916cd2Sjpk */ 113045916cd2Sjpk nuid = (stat_buf.st_uid == uid) ? uid : stat_buf.st_uid; 113145916cd2Sjpk error = exec_clean(optflag, da->da_devname, da->da_devexec, nuid, 113245916cd2Sjpk devzone, DEALLOC_CLEAN); 113345916cd2Sjpk if (error != 0) { 113445916cd2Sjpk if (!(optflag & (FORCE | FORCE_ALL))) { 113545916cd2Sjpk error = CLEANERR; 113645916cd2Sjpk (void) mk_error(dm); 113745916cd2Sjpk } else { 113845916cd2Sjpk error = 0; 113945916cd2Sjpk } 114045916cd2Sjpk } 114145916cd2Sjpk 114245916cd2Sjpk out: 114345916cd2Sjpk if (dm_new) 114445916cd2Sjpk freedmapent(dm_new); 114545916cd2Sjpk return (error); 114645916cd2Sjpk } 114745916cd2Sjpk 114845916cd2Sjpk int 114910ddde3aSaj _allocate_dev(int optflag, uid_t uid, devalloc_t *da, char *zonename, 115010ddde3aSaj int *lock_fd) 115145916cd2Sjpk { 115245916cd2Sjpk int i; 115345916cd2Sjpk int bytes = 0; 115445916cd2Sjpk int error = 0; 115545916cd2Sjpk int is_authorized = 0; 115645916cd2Sjpk int dealloc_optflag = 0; 115745916cd2Sjpk char *fname = NULL; 115845916cd2Sjpk char file_name[MAXPATHLEN]; 115945916cd2Sjpk devmap_t *dm; 116045916cd2Sjpk struct stat stat_buf; 116145916cd2Sjpk struct state_file sf; 116245916cd2Sjpk struct zone_path zpath; 116345916cd2Sjpk 116445916cd2Sjpk zpath.count = 0; 116545916cd2Sjpk zpath.path = NULL; 116645916cd2Sjpk setdmapent(); 116745916cd2Sjpk if ((dm = getdmapnam(da->da_devname)) == NULL) { 116845916cd2Sjpk enddmapent(); 116945916cd2Sjpk dprintf("Unable to find %s in device map database\n", 117045916cd2Sjpk da->da_devname); 117145916cd2Sjpk return (NODMAPERR); 117245916cd2Sjpk } 117345916cd2Sjpk enddmapent(); 117445916cd2Sjpk if (system_labeled) { 117545916cd2Sjpk if (_dev_file_name(&sf, dm) != 0) { 117645916cd2Sjpk freedmapent(dm); 117745916cd2Sjpk dprintf("Unable to find %s device files\n", 117845916cd2Sjpk da->da_devname); 117945916cd2Sjpk error = NODMAPERR; 118045916cd2Sjpk goto out; 118145916cd2Sjpk } 118245916cd2Sjpk fname = sf.sf_path; 118345916cd2Sjpk } else { 118445916cd2Sjpk bytes = snprintf(file_name, MAXPATHLEN, "%s/%s", DAC_DIR, 118545916cd2Sjpk da->da_devname); 118645916cd2Sjpk if (bytes <= 0) { 118745916cd2Sjpk error = DEVNAMEERR; 118845916cd2Sjpk goto out; 118945916cd2Sjpk } else if (bytes >= MAXPATHLEN) { 119045916cd2Sjpk dprintf("device name %s is too long.\n", 119145916cd2Sjpk da->da_devname); 119245916cd2Sjpk error = DEVLONGERR; 119345916cd2Sjpk goto out; 119445916cd2Sjpk } 119545916cd2Sjpk fname = file_name; 119645916cd2Sjpk } 119745916cd2Sjpk 119845916cd2Sjpk (void) audit_allocate_device(fname); 119945916cd2Sjpk 120045916cd2Sjpk if (stat(fname, &stat_buf) != 0) { 120145916cd2Sjpk dprintf("Unable to stat %s\n", fname); 12027c478bd9Sstevel@tonic-gate dperror("Error:"); 120345916cd2Sjpk error = DACACCERR; 120445916cd2Sjpk goto out; 12057c478bd9Sstevel@tonic-gate } 120645916cd2Sjpk if (DEV_ERRORED(stat_buf)) { 120745916cd2Sjpk error = DEVSTATEERR; 120845916cd2Sjpk goto out; 120945916cd2Sjpk } 121045916cd2Sjpk is_authorized = _is_dev_authorized(da, uid); 121145916cd2Sjpk if (is_authorized == ALLOC_BY_NONE) { 121245916cd2Sjpk dprintf("Device %s is not allocatable\n", da->da_devname); 121345916cd2Sjpk error = UAUTHERR; 121445916cd2Sjpk goto out; 121545916cd2Sjpk } else if (!is_authorized && !(optflag & USERNAME)) { 121645916cd2Sjpk dprintf("User %d is unauthorized to allocate\n", (int)uid); 121745916cd2Sjpk error = UAUTHERR; 121845916cd2Sjpk goto out; 121945916cd2Sjpk } 122045916cd2Sjpk if (system_labeled) { 122145916cd2Sjpk /* 122245916cd2Sjpk * check if label of the zone to which the device is being 122345916cd2Sjpk * allocated is within the device label range. 122445916cd2Sjpk */ 122545916cd2Sjpk if (_check_label(da, zonename, uid, CHECK_DRANGE) != 0) { 122645916cd2Sjpk error = LABELRNGERR; 122745916cd2Sjpk goto out; 122845916cd2Sjpk } 122945916cd2Sjpk } 123045916cd2Sjpk if (check_devs(dm) == -1) { 123145916cd2Sjpk error = DSPMISSERR; 123245916cd2Sjpk goto out; 123345916cd2Sjpk } 12347c478bd9Sstevel@tonic-gate if (DEV_ALLOCATED(stat_buf)) { 123545916cd2Sjpk if (optflag & FORCE) { 123645916cd2Sjpk if (optflag & SILENT) 123745916cd2Sjpk dealloc_optflag = FORCE|SILENT; 123840e2b7c9Spaulson else 123945916cd2Sjpk dealloc_optflag = FORCE; 124045916cd2Sjpk if (_deallocate_dev(dealloc_optflag, da, dm, uid, 124110ddde3aSaj zonename, lock_fd)) { 12427c478bd9Sstevel@tonic-gate dprintf("Couldn't force deallocate device %s\n", 124345916cd2Sjpk da->da_devname); 124445916cd2Sjpk error = CNTFRCERR; 124545916cd2Sjpk goto out; 12467c478bd9Sstevel@tonic-gate } 12477c478bd9Sstevel@tonic-gate } else if (stat_buf.st_uid == uid) { 124845916cd2Sjpk error = PREALLOCERR; 124945916cd2Sjpk goto out; 12507c478bd9Sstevel@tonic-gate } else { 125145916cd2Sjpk error = ALLOCUERR; 125245916cd2Sjpk goto out; 125345916cd2Sjpk } 125445916cd2Sjpk } 125545916cd2Sjpk /* All checks passed, time to lock and allocate */ 125610ddde3aSaj if ((*lock_fd = lock_dev(fname, &stat_buf)) == -1) { 125710ddde3aSaj error = DEVLKERR; 125845916cd2Sjpk goto out; 125910ddde3aSaj } 126045916cd2Sjpk if (system_labeled) { 126145916cd2Sjpk /* 126245916cd2Sjpk * Run the cleaning program; it also mounts allocated 126345916cd2Sjpk * device if required. 126445916cd2Sjpk */ 126545916cd2Sjpk error = exec_clean(optflag, da->da_devname, da->da_devexec, uid, 126645916cd2Sjpk zonename, ALLOC_CLEAN); 126710ddde3aSaj if (error != DEVCLEAN_OK) { 126810ddde3aSaj switch (error) { 126910ddde3aSaj case DEVCLEAN_ERROR: 127010ddde3aSaj case DEVCLEAN_SYSERR: 127110ddde3aSaj dprintf("allocate: " 127210ddde3aSaj "Error in device clean program %s\n", 127310ddde3aSaj da->da_devexec); 127445916cd2Sjpk error = CLEANERR; 127545916cd2Sjpk (void) mk_error(dm); 127645916cd2Sjpk goto out; 127710ddde3aSaj case DEVCLEAN_BADMOUNT: 127810ddde3aSaj dprintf("allocate: Failed to mount device %s\n", 127910ddde3aSaj da->da_devexec); 128010ddde3aSaj goto out; 128110ddde3aSaj case DEVCLEAN_MOUNTOK: 128210ddde3aSaj break; 128310ddde3aSaj default: 128410ddde3aSaj error = 0; 128510ddde3aSaj goto out; 128610ddde3aSaj } 128745916cd2Sjpk } 128845916cd2Sjpk /* 128945916cd2Sjpk * If not mounted, create zonelinks, if this is not the 129045916cd2Sjpk * global zone. 129145916cd2Sjpk */ 129245916cd2Sjpk if ((strcmp(zonename, GLOBAL_ZONENAME) != 0) && 129310ddde3aSaj (error != DEVCLEAN_MOUNTOK)) { 129445916cd2Sjpk if (create_znode(zonename, &zpath, dm) != 0) { 129545916cd2Sjpk error = ZONEERR; 129645916cd2Sjpk goto out; 129745916cd2Sjpk } 129845916cd2Sjpk } 129945916cd2Sjpk } 130045916cd2Sjpk 130145916cd2Sjpk (void) audit_allocate_list(dm->dmap_devlist); 130245916cd2Sjpk 130345916cd2Sjpk if ((error = mk_alloc(dm, uid, &zpath)) != 0) { 130445916cd2Sjpk (void) mk_unalloc(optflag, dm); 130545916cd2Sjpk goto out; 130645916cd2Sjpk } 130745916cd2Sjpk 130845916cd2Sjpk if (system_labeled == 0) { 130945916cd2Sjpk if ((error = _newdac(file_name, uid, getgid(), 131045916cd2Sjpk ALLOC_MODE)) != 0) { 131110ddde3aSaj (void) _newdac(file_name, DA_UID, DA_GID, 131245916cd2Sjpk ALLOC_ERR_MODE); 131345916cd2Sjpk goto out; 131445916cd2Sjpk } 131545916cd2Sjpk } 131645916cd2Sjpk error = 0; 131745916cd2Sjpk out: 131845916cd2Sjpk if (zpath.count) { 131945916cd2Sjpk for (i = 0; i < zpath.count; i++) 132045916cd2Sjpk free(zpath.path[i]); 132145916cd2Sjpk free(zpath.path); 132245916cd2Sjpk } 132345916cd2Sjpk freedmapent(dm); 132445916cd2Sjpk return (error); 132545916cd2Sjpk } 132645916cd2Sjpk 132745916cd2Sjpk void 1328facf4a8dSllai1 _store_devnames(int *count, struct dev_names *dnms, char *zonename, 132945916cd2Sjpk devalloc_t *da, int flag) 133045916cd2Sjpk { 133145916cd2Sjpk int i; 133245916cd2Sjpk 133345916cd2Sjpk dnms->dnames = (char **)realloc(dnms->dnames, 133445916cd2Sjpk (*count + 1) * sizeof (char *)); 133545916cd2Sjpk if (da) { 133645916cd2Sjpk dnms->dnames[*count] = strdup(da->da_devname); 133745916cd2Sjpk (*count)++; 133845916cd2Sjpk } else { 133945916cd2Sjpk dnms->dnames[*count] = NULL; 134045916cd2Sjpk if (flag == DA_ADD_ZONE) 134145916cd2Sjpk (void) update_device(dnms->dnames, zonename, 134245916cd2Sjpk DA_ADD_ZONE); 134345916cd2Sjpk else if (flag == DA_REMOVE_ZONE) 134445916cd2Sjpk (void) update_device(dnms->dnames, NULL, 134545916cd2Sjpk DA_REMOVE_ZONE); 134645916cd2Sjpk for (i = 0; i < *count; i++) 134745916cd2Sjpk free(dnms->dnames[i]); 134845916cd2Sjpk free(dnms->dnames); 134945916cd2Sjpk } 135045916cd2Sjpk } 135145916cd2Sjpk 135245916cd2Sjpk int 135345916cd2Sjpk allocate(int optflag, uid_t uid, char *device, char *zonename) 135445916cd2Sjpk { 135545916cd2Sjpk int count = 0; 135645916cd2Sjpk int error = 0; 135710ddde3aSaj int lock_fd = -1; 135845916cd2Sjpk devalloc_t *da; 1359facf4a8dSllai1 struct dev_names dnms; 136045916cd2Sjpk 136145916cd2Sjpk if (optflag & (FORCE | USERID | USERNAME)) { 136245916cd2Sjpk if (!_is_authorized(DEVICE_REVOKE_AUTH, getuid())) 136345916cd2Sjpk return (UAUTHERR); 136445916cd2Sjpk } 136545916cd2Sjpk dnms.dnames = NULL; 136645916cd2Sjpk setdaent(); 136745916cd2Sjpk if (optflag & TYPE) { 136845916cd2Sjpk /* 136945916cd2Sjpk * allocate devices of this type 137045916cd2Sjpk */ 137145916cd2Sjpk while ((da = getdatype(device)) != NULL) { 137245916cd2Sjpk if (system_labeled && 137345916cd2Sjpk da_check_logindevperm(da->da_devname)) { 137445916cd2Sjpk freedaent(da); 13757c478bd9Sstevel@tonic-gate continue; 13767c478bd9Sstevel@tonic-gate } 137745916cd2Sjpk dprintf("trying to allocate %s\n", da->da_devname); 137810ddde3aSaj error = _allocate_dev(optflag, uid, da, zonename, 137910ddde3aSaj &lock_fd); 138045916cd2Sjpk if (system_labeled && (error == 0)) { 138145916cd2Sjpk /* 138245916cd2Sjpk * we need to record in device_allocate the 138345916cd2Sjpk * label (zone name) at which this device is 138445916cd2Sjpk * being allocated. store this device entry. 138545916cd2Sjpk */ 138645916cd2Sjpk _store_devnames(&count, &dnms, zonename, da, 0); 13877c478bd9Sstevel@tonic-gate } 138845916cd2Sjpk freedaent(da); 138945916cd2Sjpk error = 0; 13907c478bd9Sstevel@tonic-gate } 139145916cd2Sjpk } else { 139245916cd2Sjpk /* 139345916cd2Sjpk * allocate this device 139445916cd2Sjpk */ 139545916cd2Sjpk if ((da = getdanam(device)) == NULL) { 13967c478bd9Sstevel@tonic-gate enddaent(); 139745916cd2Sjpk return (NODAERR); 139845916cd2Sjpk } 139945916cd2Sjpk if (system_labeled && da_check_logindevperm(device)) { 140045916cd2Sjpk freedaent(da); 140145916cd2Sjpk return (LOGINDEVPERMERR); 140245916cd2Sjpk } 140345916cd2Sjpk dprintf("trying to allocate %s\n", da->da_devname); 140410ddde3aSaj error = _allocate_dev(optflag, uid, da, zonename, &lock_fd); 140545916cd2Sjpk /* 140645916cd2Sjpk * we need to record in device_allocate the label (zone name) 140745916cd2Sjpk * at which this device is being allocated. store this device 140845916cd2Sjpk * entry. 140945916cd2Sjpk */ 141045916cd2Sjpk if (system_labeled && (error == 0)) 141145916cd2Sjpk _store_devnames(&count, &dnms, zonename, da, 0); 141245916cd2Sjpk freedaent(da); 141310ddde3aSaj if (error == DEVCLEAN_BADMOUNT) 141410ddde3aSaj error = 0; 141545916cd2Sjpk } 141645916cd2Sjpk enddaent(); 141710ddde3aSaj if (lock_fd != -1) 141810ddde3aSaj (void) close(lock_fd); 141945916cd2Sjpk /* 142045916cd2Sjpk * add to device_allocate labels (zone names) for the devices we 142145916cd2Sjpk * allocated. 142245916cd2Sjpk */ 142345916cd2Sjpk if (dnms.dnames) 142445916cd2Sjpk _store_devnames(&count, &dnms, zonename, NULL, DA_ADD_ZONE); 142545916cd2Sjpk 14267c478bd9Sstevel@tonic-gate return (error); 14277c478bd9Sstevel@tonic-gate } 142845916cd2Sjpk 142945916cd2Sjpk /* ARGSUSED */ 143045916cd2Sjpk int 143145916cd2Sjpk deallocate(int optflag, uid_t uid, char *device, char *zonename) 143245916cd2Sjpk { 143345916cd2Sjpk int count = 0; 143445916cd2Sjpk int error = 0; 143510ddde3aSaj int lock_fd = -1; 143610ddde3aSaj char *class = NULL; 143745916cd2Sjpk devalloc_t *da; 1438facf4a8dSllai1 struct dev_names dnms; 143945916cd2Sjpk 144045916cd2Sjpk if (optflag & (FORCE | FORCE_ALL)) { 144145916cd2Sjpk if (!_is_authorized(DEVICE_REVOKE_AUTH, getuid())) 144245916cd2Sjpk return (UAUTHERR); 144345916cd2Sjpk } 144445916cd2Sjpk if (optflag & FORCE_ALL) 144545916cd2Sjpk optflag |= FORCE; 144645916cd2Sjpk dnms.dnames = NULL; 144745916cd2Sjpk setdaent(); 144845916cd2Sjpk if (optflag & FORCE_ALL) { 144945916cd2Sjpk /* 145045916cd2Sjpk * deallocate all devices 145145916cd2Sjpk */ 145245916cd2Sjpk while ((da = getdaent()) != NULL) { 145345916cd2Sjpk if (system_labeled && 145445916cd2Sjpk da_check_logindevperm(da->da_devname)) { 145545916cd2Sjpk freedaent(da); 145645916cd2Sjpk continue; 145745916cd2Sjpk } 145845916cd2Sjpk dprintf("trying to deallocate %s\n", da->da_devname); 145945916cd2Sjpk error = _deallocate_dev(optflag, da, NULL, uid, 146010ddde3aSaj zonename, &lock_fd); 146145916cd2Sjpk if (system_labeled && (error == 0)) { 146245916cd2Sjpk /* 146345916cd2Sjpk * we need to remove this device's allocation 146445916cd2Sjpk * label (zone name) from device_allocate. 146545916cd2Sjpk * store this device name. 146645916cd2Sjpk */ 146745916cd2Sjpk _store_devnames(&count, &dnms, zonename, da, 0); 146845916cd2Sjpk } 146945916cd2Sjpk freedaent(da); 147045916cd2Sjpk error = 0; 147145916cd2Sjpk } 147210ddde3aSaj } else if (system_labeled && (optflag & TYPE)) { 147345916cd2Sjpk /* 147445916cd2Sjpk * deallocate all devices of this type 147545916cd2Sjpk */ 147645916cd2Sjpk while ((da = getdatype(device)) != NULL) { 147745916cd2Sjpk if (da_check_logindevperm(da->da_devname)) { 147845916cd2Sjpk freedaent(da); 147945916cd2Sjpk continue; 148045916cd2Sjpk } 148145916cd2Sjpk dprintf("trying to deallocate %s\n", da->da_devname); 148245916cd2Sjpk error = _deallocate_dev(optflag, da, NULL, uid, 148310ddde3aSaj zonename, &lock_fd); 148445916cd2Sjpk if (error == 0) { 148545916cd2Sjpk /* 148645916cd2Sjpk * we need to remove this device's allocation 148745916cd2Sjpk * label (zone name) from device_allocate. 148845916cd2Sjpk * store this device name. 148945916cd2Sjpk */ 149045916cd2Sjpk _store_devnames(&count, &dnms, zonename, da, 0); 149145916cd2Sjpk } 149245916cd2Sjpk freedaent(da); 149345916cd2Sjpk error = 0; 149445916cd2Sjpk } 149510ddde3aSaj } else if (system_labeled && (optflag & CLASS)) { 149610ddde3aSaj /* 149710ddde3aSaj * deallocate all devices of this class (for sunray) 149810ddde3aSaj */ 149910ddde3aSaj while ((da = getdaent()) != NULL) { 150010ddde3aSaj class = kva_match(da->da_devopts, DAOPT_CLASS); 150110ddde3aSaj if (class && (strcmp(class, device) == 0)) { 150210ddde3aSaj dprintf("trying to deallocate %s\n", 150310ddde3aSaj da->da_devname); 150410ddde3aSaj error = _deallocate_dev(optflag, da, NULL, uid, 150510ddde3aSaj zonename, &lock_fd); 150610ddde3aSaj if (error == 0) { 150710ddde3aSaj /* 150810ddde3aSaj * we need to remove this device's 150910ddde3aSaj * allocation label (zone name) from 151010ddde3aSaj * device_allocate. store this device 151110ddde3aSaj * name. 151210ddde3aSaj */ 151310ddde3aSaj _store_devnames(&count, &dnms, zonename, 151410ddde3aSaj da, 0); 151510ddde3aSaj } 151610ddde3aSaj error = 0; 151710ddde3aSaj } 151810ddde3aSaj freedaent(da); 151910ddde3aSaj } 152045916cd2Sjpk } else if (!(optflag & TYPE)) { 152145916cd2Sjpk /* 152245916cd2Sjpk * deallocate this device 152345916cd2Sjpk */ 152445916cd2Sjpk if ((da = getdanam(device)) == NULL) { 152545916cd2Sjpk enddaent(); 152645916cd2Sjpk return (NODAERR); 152745916cd2Sjpk } 152845916cd2Sjpk if (system_labeled && da_check_logindevperm(da->da_devname)) { 152945916cd2Sjpk freedaent(da); 153045916cd2Sjpk return (LOGINDEVPERMERR); 153145916cd2Sjpk } 153245916cd2Sjpk dprintf("trying to deallocate %s\n", da->da_devname); 153310ddde3aSaj error = _deallocate_dev(optflag, da, NULL, uid, zonename, 153410ddde3aSaj &lock_fd); 153545916cd2Sjpk if (system_labeled && (error == 0)) { 153645916cd2Sjpk /* 153745916cd2Sjpk * we need to remove this device's allocation label 153845916cd2Sjpk * (zone name) from device_allocate. store this 153945916cd2Sjpk * device name. 154045916cd2Sjpk */ 154145916cd2Sjpk _store_devnames(&count, &dnms, zonename, da, 0); 154245916cd2Sjpk } 154345916cd2Sjpk freedaent(da); 154410ddde3aSaj if (error == DEVCLEAN_BADMOUNT) 154510ddde3aSaj error = 0; 154645916cd2Sjpk } 154745916cd2Sjpk enddaent(); 154810ddde3aSaj if (lock_fd != -1) 154910ddde3aSaj (void) close(lock_fd); 155045916cd2Sjpk /* 155145916cd2Sjpk * remove from device_allocate labels (zone names) for the devices we 155245916cd2Sjpk * deallocated. 155345916cd2Sjpk */ 155445916cd2Sjpk if (dnms.dnames) 155545916cd2Sjpk _store_devnames(&count, &dnms, zonename, NULL, DA_REMOVE_ZONE); 155645916cd2Sjpk 155745916cd2Sjpk return (error); 155845916cd2Sjpk } 155945916cd2Sjpk 156045916cd2Sjpk static int 156145916cd2Sjpk _dev_file_name(struct state_file *sfp, devmap_t *dm) 156245916cd2Sjpk { 156345916cd2Sjpk sfp->sf_flags = 0; 156445916cd2Sjpk /* if devlist is generated, never leave device in error state */ 156545916cd2Sjpk if (dm->dmap_devlist[0] == '`') 156645916cd2Sjpk sfp->sf_flags |= SFF_NO_ERROR; 156745916cd2Sjpk if (dm->dmap_devarray == NULL || 156845916cd2Sjpk dm->dmap_devarray[0] == NULL) 156945916cd2Sjpk return (NODMAPERR); 157045916cd2Sjpk (void) strncpy(sfp->sf_path, dm->dmap_devarray[0], 157145916cd2Sjpk sizeof (sfp->sf_path)); 157245916cd2Sjpk sfp->sf_path[sizeof (sfp->sf_path) - 1] = '\0'; 157345916cd2Sjpk if (sfp->sf_path[0] == '\0') { 157445916cd2Sjpk dprintf("dev_file_name: no device list for %s\n", 157545916cd2Sjpk dm->dmap_devname); 157645916cd2Sjpk return (NODMAPERR); 157745916cd2Sjpk } 157845916cd2Sjpk 157945916cd2Sjpk return (0); 158045916cd2Sjpk } 158145916cd2Sjpk 158245916cd2Sjpk /* 158345916cd2Sjpk * _check_label - 158445916cd2Sjpk * checks the device label range against zone label, which is also 158545916cd2Sjpk * user's current label. 158645916cd2Sjpk * returns 0 if in range, -1 for all other conditions. 158745916cd2Sjpk * 158845916cd2Sjpk */ 158945916cd2Sjpk 159045916cd2Sjpk static int 159145916cd2Sjpk _check_label(devalloc_t *da, char *zonename, uid_t uid, int flag) 159245916cd2Sjpk { 159345916cd2Sjpk int err; 159445916cd2Sjpk int in_range = 0; 159545916cd2Sjpk char *alloczone, *lstr; 159645916cd2Sjpk char pw_buf[NSS_BUFLEN_PASSWD]; 159745916cd2Sjpk blrange_t *range; 159845916cd2Sjpk m_label_t *zlabel; 159945916cd2Sjpk struct passwd pw_ent; 160045916cd2Sjpk 160145916cd2Sjpk if ((da == NULL) || (zonename == NULL)) 160245916cd2Sjpk return (-1); 160345916cd2Sjpk 160445916cd2Sjpk if ((zlabel = getzonelabelbyname(zonename)) == NULL) { 160545916cd2Sjpk dprintf("unable to get label for %s zone\n", zonename); 160645916cd2Sjpk return (-1); 160745916cd2Sjpk } 160845916cd2Sjpk if (flag == CHECK_DRANGE) { 160945916cd2Sjpk blrange_t drange; 161045916cd2Sjpk 161145916cd2Sjpk drange.lower_bound = blabel_alloc(); 161245916cd2Sjpk lstr = kva_match(da->da_devopts, DAOPT_MINLABEL); 161345916cd2Sjpk if (lstr == NULL) { 161445916cd2Sjpk bsllow(drange.lower_bound); 161545916cd2Sjpk } else if (stobsl(lstr, drange.lower_bound, NO_CORRECTION, 161645916cd2Sjpk &err) == 0) { 161745916cd2Sjpk dprintf("bad min_label for device %s\n", 161845916cd2Sjpk da->da_devname); 161945916cd2Sjpk free(zlabel); 162045916cd2Sjpk blabel_free(drange.lower_bound); 162145916cd2Sjpk return (-1); 162245916cd2Sjpk } 162345916cd2Sjpk drange.upper_bound = blabel_alloc(); 162445916cd2Sjpk lstr = kva_match(da->da_devopts, DAOPT_MAXLABEL); 162545916cd2Sjpk if (lstr == NULL) { 162645916cd2Sjpk bslhigh(drange.upper_bound); 162745916cd2Sjpk } else if (stobsl(lstr, drange.upper_bound, NO_CORRECTION, 162845916cd2Sjpk &err) == 0) { 162945916cd2Sjpk dprintf("bad max_label for device %s\n", 163045916cd2Sjpk da->da_devname); 163145916cd2Sjpk free(zlabel); 163245916cd2Sjpk blabel_free(drange.lower_bound); 163345916cd2Sjpk blabel_free(drange.upper_bound); 163445916cd2Sjpk return (-1); 163545916cd2Sjpk } 163645916cd2Sjpk if (blinrange(zlabel, &drange) == 0) { 163745916cd2Sjpk char *zlbl = NULL, *min = NULL, *max = NULL; 163845916cd2Sjpk 163945916cd2Sjpk (void) bsltos(zlabel, &zlbl, 0, 0); 164045916cd2Sjpk (void) bsltos(drange.lower_bound, &min, 0, 0); 164145916cd2Sjpk (void) bsltos(drange.upper_bound, &max, 0, 0); 164245916cd2Sjpk dprintf("%s zone label ", zonename); 164345916cd2Sjpk dprintf("%s outside device label range: ", zlbl); 164445916cd2Sjpk dprintf("min - %s, ", min); 164545916cd2Sjpk dprintf("max - %s\n", max); 164645916cd2Sjpk free(zlabel); 164745916cd2Sjpk blabel_free(drange.lower_bound); 164845916cd2Sjpk blabel_free(drange.upper_bound); 164945916cd2Sjpk return (-1); 165045916cd2Sjpk } 165145916cd2Sjpk } else if (flag == CHECK_URANGE) { 165245916cd2Sjpk if (getpwuid_r(uid, &pw_ent, pw_buf, sizeof (pw_buf)) == NULL) { 165345916cd2Sjpk dprintf("Unable to get passwd entry for userid %d\n", 165445916cd2Sjpk (int)uid); 165545916cd2Sjpk free(zlabel); 165645916cd2Sjpk return (-1); 165745916cd2Sjpk } 165845916cd2Sjpk if ((range = getuserrange(pw_ent.pw_name)) == NULL) { 165945916cd2Sjpk dprintf("Unable to get label range for userid %d\n", 166045916cd2Sjpk (int)uid); 166145916cd2Sjpk free(zlabel); 166245916cd2Sjpk return (-1); 166345916cd2Sjpk } 166445916cd2Sjpk in_range = blinrange(zlabel, range); 166545916cd2Sjpk free(zlabel); 166645916cd2Sjpk blabel_free(range->lower_bound); 166745916cd2Sjpk blabel_free(range->upper_bound); 166845916cd2Sjpk free(range); 166945916cd2Sjpk if (in_range == 0) { 167045916cd2Sjpk dprintf("%s device label ", da->da_devname); 167145916cd2Sjpk dprintf("out of user %d label range\n", (int)uid); 167245916cd2Sjpk return (-1); 167345916cd2Sjpk } 167445916cd2Sjpk } else if (flag == CHECK_ZLABEL) { 167545916cd2Sjpk alloczone = kva_match(da->da_devopts, DAOPT_ZONE); 167645916cd2Sjpk if (alloczone == NULL) { 167745916cd2Sjpk free(zlabel); 167845916cd2Sjpk return (-1); 167945916cd2Sjpk } 168045916cd2Sjpk if (strcmp(zonename, alloczone) != 0) { 168145916cd2Sjpk dprintf("%s zone is different than ", zonename); 168245916cd2Sjpk dprintf("%s zone to which the device ", alloczone); 168345916cd2Sjpk dprintf("%s is allocated\n", da->da_devname); 168445916cd2Sjpk free(zlabel); 168545916cd2Sjpk return (-1); 168645916cd2Sjpk } 168745916cd2Sjpk } 168845916cd2Sjpk free(zlabel); 168945916cd2Sjpk 169045916cd2Sjpk return (0); 169145916cd2Sjpk } 169245916cd2Sjpk 169345916cd2Sjpk int 169445916cd2Sjpk create_znode(char *zonename, struct zone_path *zpath, devmap_t *list) 169545916cd2Sjpk { 169645916cd2Sjpk int size; 169745916cd2Sjpk int len = 0; 169845916cd2Sjpk int fcount = 0; 169945916cd2Sjpk char *p, *tmpfile, *zoneroot; 170045916cd2Sjpk char **file; 170145916cd2Sjpk char zonepath[MAXPATHLEN]; 1702facf4a8dSllai1 di_prof_t prof = NULL; 170345916cd2Sjpk 170445916cd2Sjpk file = list->dmap_devarray; 170545916cd2Sjpk if (file == NULL) 170645916cd2Sjpk return (NODMAPERR); 170745916cd2Sjpk if ((zoneroot = getzonerootbyname(zonename)) == NULL) { 170845916cd2Sjpk dprintf("unable to get label for %s zone\n", zonename); 170945916cd2Sjpk return (1); 171045916cd2Sjpk } 171145916cd2Sjpk (void) strcpy(zonepath, zoneroot); 171245916cd2Sjpk free(zoneroot); 171345916cd2Sjpk len = strlen(zonepath); 171445916cd2Sjpk size = sizeof (zonepath); 1715facf4a8dSllai1 (void) strlcat(zonepath, "/dev", size); 1716facf4a8dSllai1 if (di_prof_init(zonepath, &prof)) { 1717facf4a8dSllai1 dprintf("failed to initialize dev profile at %s\n", zonepath); 171845916cd2Sjpk return (1); 171945916cd2Sjpk } 1720facf4a8dSllai1 zonepath[len] = '\0'; 1721facf4a8dSllai1 for (; *file != NULL; file++) { 172245916cd2Sjpk /* 172345916cd2Sjpk * First time initialization 172445916cd2Sjpk */ 172545916cd2Sjpk tmpfile = strdup(*file); 172645916cd2Sjpk 172745916cd2Sjpk /* 172845916cd2Sjpk * Most devices have pathnames starting in /dev 172945916cd2Sjpk * but SunRay devices do not. In SRRS 3.1 they use /tmp. 173045916cd2Sjpk * 173145916cd2Sjpk * If the device pathname is not in /dev then create 173245916cd2Sjpk * a symbolic link to it and put the device in /dev 173345916cd2Sjpk */ 173445916cd2Sjpk if (strncmp(tmpfile, "/dev/", strlen("/dev/")) != 0) { 173545916cd2Sjpk char *linkdir; 173645916cd2Sjpk char srclinkdir[MAXPATHLEN]; 173745916cd2Sjpk char dstlinkdir[MAXPATHLEN]; 173845916cd2Sjpk 173945916cd2Sjpk linkdir = strchr(tmpfile + 1, '/'); 174045916cd2Sjpk p = strchr(linkdir + 1, '/'); 174145916cd2Sjpk *p = '\0'; 174245916cd2Sjpk (void) strcpy(dstlinkdir, "/dev"); 174345916cd2Sjpk (void) strncat(dstlinkdir, linkdir, MAXPATHLEN); 174445916cd2Sjpk (void) snprintf(srclinkdir, MAXPATHLEN, "%s/root%s", 174545916cd2Sjpk zonepath, tmpfile); 174645916cd2Sjpk (void) symlink(dstlinkdir, srclinkdir); 174745916cd2Sjpk *p = '/'; 174845916cd2Sjpk (void) strncat(dstlinkdir, p, MAXPATHLEN); 174945916cd2Sjpk free(tmpfile); 175045916cd2Sjpk tmpfile = strdup(dstlinkdir); 175145916cd2Sjpk } 1752facf4a8dSllai1 if (di_prof_add_dev(prof, tmpfile)) { 1753facf4a8dSllai1 dprintf("failed to add %s to profile\n", tmpfile); 1754facf4a8dSllai1 di_prof_fini(prof); 175545916cd2Sjpk return (1); 175645916cd2Sjpk } 175745916cd2Sjpk if (strlcat(zonepath, tmpfile, size) >= size) { 175845916cd2Sjpk dprintf("Buffer overflow in create_znode for %s\n", 175945916cd2Sjpk *file); 176045916cd2Sjpk free(tmpfile); 1761facf4a8dSllai1 di_prof_fini(prof); 176245916cd2Sjpk return (1); 176345916cd2Sjpk } 176445916cd2Sjpk free(tmpfile); 176545916cd2Sjpk fcount++; 176645916cd2Sjpk if ((zpath->path = (char **)realloc(zpath->path, 1767facf4a8dSllai1 (fcount * sizeof (char *)))) == NULL) { 1768facf4a8dSllai1 di_prof_fini(prof); 176945916cd2Sjpk return (1); 1770facf4a8dSllai1 } 177145916cd2Sjpk zpath->path[zpath->count] = strdup(zonepath); 177245916cd2Sjpk zpath->count = fcount; 177345916cd2Sjpk zonepath[len] = '\0'; 177445916cd2Sjpk } 177545916cd2Sjpk 1776facf4a8dSllai1 if (di_prof_commit(prof)) 1777facf4a8dSllai1 dprintf("failed to add devices to zone %s\n", zonename); 1778facf4a8dSllai1 di_prof_fini(prof); 1779facf4a8dSllai1 178045916cd2Sjpk return (0); 178145916cd2Sjpk } 178245916cd2Sjpk 178345916cd2Sjpk int 178445916cd2Sjpk remove_znode(char *zonename, devmap_t *dm) 178545916cd2Sjpk { 178645916cd2Sjpk int len = 0; 178745916cd2Sjpk char *zoneroot; 178845916cd2Sjpk char **file; 178945916cd2Sjpk char zonepath[MAXPATHLEN]; 1790facf4a8dSllai1 di_prof_t prof = NULL; 179145916cd2Sjpk 179245916cd2Sjpk file = dm->dmap_devarray; 179345916cd2Sjpk if (file == NULL) 179445916cd2Sjpk return (NODMAPERR); 179545916cd2Sjpk if ((zoneroot = getzonerootbyname(zonename)) == NULL) { 179645916cd2Sjpk (void) snprintf(zonepath, MAXPATHLEN, "/zone/%s", zonename); 179745916cd2Sjpk } else { 179845916cd2Sjpk (void) strcpy(zonepath, zoneroot); 179945916cd2Sjpk free(zoneroot); 180045916cd2Sjpk } 180145916cd2Sjpk /* 180245916cd2Sjpk * To support SunRay we will just deal with the 180345916cd2Sjpk * file in /dev, not the symlinks. 180445916cd2Sjpk */ 180545916cd2Sjpk (void) strncat(zonepath, "/dev", MAXPATHLEN); 180645916cd2Sjpk len = strlen(zonepath); 1807facf4a8dSllai1 if (di_prof_init(zonepath, &prof)) { 1808facf4a8dSllai1 dprintf("failed to initialize dev profile at %s\n", zonepath); 1809facf4a8dSllai1 return (1); 1810facf4a8dSllai1 } 181145916cd2Sjpk for (; *file != NULL; file++) { 181245916cd2Sjpk char *devrelpath; 181345916cd2Sjpk 181445916cd2Sjpk /* 181545916cd2Sjpk * remove device node from zone. 181645916cd2Sjpk * 181745916cd2Sjpk * SunRay devices don't start with /dev 181845916cd2Sjpk * so skip over first directory to make 181945916cd2Sjpk * sure it is /dev. SunRay devices in zones 182045916cd2Sjpk * will have a symlink into /dev but 182145916cd2Sjpk * we don't ever delete it. 182245916cd2Sjpk */ 182345916cd2Sjpk devrelpath = strchr(*file + 1, '/'); 182445916cd2Sjpk 1825facf4a8dSllai1 if (di_prof_add_exclude(prof, devrelpath + 1)) { 1826facf4a8dSllai1 dprintf("Failed exclude %s in dev profile\n", *file); 1827facf4a8dSllai1 di_prof_fini(prof); 182845916cd2Sjpk return (1); 182945916cd2Sjpk } 183045916cd2Sjpk zonepath[len] = '\0'; 183145916cd2Sjpk } 183245916cd2Sjpk 1833facf4a8dSllai1 if (di_prof_commit(prof)) 1834facf4a8dSllai1 dprintf("failed to remove devices from zone %s\n", zonename); 1835facf4a8dSllai1 di_prof_fini(prof); 183645916cd2Sjpk return (0); 183745916cd2Sjpk } 183845916cd2Sjpk 183945916cd2Sjpk int 184045916cd2Sjpk update_device(char **devnames, char *zonename, int flag) 184145916cd2Sjpk { 184245916cd2Sjpk int len, rc; 184345916cd2Sjpk char *optstr = NULL; 184445916cd2Sjpk da_args dargs; 184545916cd2Sjpk devinfo_t devinfo; 184645916cd2Sjpk 184745916cd2Sjpk dargs.optflag = flag; 184845916cd2Sjpk dargs.optflag |= DA_UPDATE|DA_ALLOC_ONLY; 184945916cd2Sjpk dargs.rootdir = NULL; 185045916cd2Sjpk dargs.devnames = devnames; 185145916cd2Sjpk devinfo.devname = devinfo.devtype = devinfo.devauths = devinfo.devexec = 185245916cd2Sjpk devinfo.devlist = NULL; 185345916cd2Sjpk if (dargs.optflag & DA_ADD_ZONE) { 185445916cd2Sjpk len = strlen(DAOPT_ZONE) + strlen(zonename) + 3; 185545916cd2Sjpk if ((optstr = (char *)malloc(len)) == NULL) 185645916cd2Sjpk return (-1); 185745916cd2Sjpk (void) snprintf(optstr, len, "%s%s%s", DAOPT_ZONE, KV_ASSIGN, 185845916cd2Sjpk zonename); 185945916cd2Sjpk devinfo.devopts = optstr; 186045916cd2Sjpk } 186145916cd2Sjpk dargs.devinfo = &devinfo; 186245916cd2Sjpk 186345916cd2Sjpk rc = da_update_device(&dargs); 186445916cd2Sjpk 186545916cd2Sjpk if (optstr) 186645916cd2Sjpk free(optstr); 186745916cd2Sjpk 186845916cd2Sjpk return (rc); 186945916cd2Sjpk } 1870