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 /* 23f48205beScasper * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #include <auth_attr.h> 307c478bd9Sstevel@tonic-gate #include <auth_list.h> 317c478bd9Sstevel@tonic-gate #include <dirent.h> 327c478bd9Sstevel@tonic-gate #include <errno.h> 337c478bd9Sstevel@tonic-gate #include <fcntl.h> 347c478bd9Sstevel@tonic-gate #include <libintl.h> 357c478bd9Sstevel@tonic-gate #include <locale.h> 367c478bd9Sstevel@tonic-gate #include <pwd.h> 377c478bd9Sstevel@tonic-gate #include <signal.h> 387c478bd9Sstevel@tonic-gate #include <stdio.h> 397c478bd9Sstevel@tonic-gate #include <stdlib.h> 407c478bd9Sstevel@tonic-gate #include <string.h> 4145916cd2Sjpk #include <strings.h> 427c478bd9Sstevel@tonic-gate #include <unistd.h> 437c478bd9Sstevel@tonic-gate #include <bsm/devices.h> 4445916cd2Sjpk #include <sys/acl.h> 4545916cd2Sjpk #include <tsol/label.h> 4645916cd2Sjpk #include <syslog.h> 4745916cd2Sjpk #include <limits.h> 4845916cd2Sjpk #include <user_attr.h> 4945916cd2Sjpk #include <secdb.h> 5045916cd2Sjpk #include <sys/mkdev.h> 517c478bd9Sstevel@tonic-gate #include <sys/acl.h> 527c478bd9Sstevel@tonic-gate #include <sys/file.h> 537c478bd9Sstevel@tonic-gate #include <sys/procfs.h> 547c478bd9Sstevel@tonic-gate #include <sys/param.h> 557c478bd9Sstevel@tonic-gate #include <sys/resource.h> 567c478bd9Sstevel@tonic-gate #include <sys/stat.h> 577c478bd9Sstevel@tonic-gate #include <sys/time.h> 587c478bd9Sstevel@tonic-gate #include <sys/types.h> 597c478bd9Sstevel@tonic-gate #include <sys/wait.h> 6045916cd2Sjpk #include <utime.h> 6145916cd2Sjpk #include <libgen.h> 6245916cd2Sjpk #include <zone.h> 6345916cd2Sjpk #include <nss_dbdefs.h> 6445916cd2Sjpk #include <bsm/devalloc.h> 65facf4a8dSllai1 #include <libdevinfo.h> 667c478bd9Sstevel@tonic-gate #include "allocate.h" 677c478bd9Sstevel@tonic-gate 6845916cd2Sjpk extern void print_error(int, char *); 6945916cd2Sjpk 7045916cd2Sjpk #if defined(DEBUG) || defined(lint) 717c478bd9Sstevel@tonic-gate #define dprintf(s, a) (void) fprintf(stderr, s, a) 727c478bd9Sstevel@tonic-gate #define dperror(s) perror(s) 737c478bd9Sstevel@tonic-gate #else /* !DEBUG */ 7445916cd2Sjpk #define dprintf(s, a) 0 7545916cd2Sjpk #define dperror(s) 0 767c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 777c478bd9Sstevel@tonic-gate 7845916cd2Sjpk #define DEV_ERRORED(sbuf) (((sbuf).st_mode & ~S_IFMT) == ALLOC_ERR_MODE) 79*10ddde3aSaj #define DEV_ALLOCATED(sbuf) ((sbuf).st_uid != DA_UID || \ 8045916cd2Sjpk !(((sbuf).st_mode & ~S_IFMT) == DEALLOC_MODE || \ 81*10ddde3aSaj DEV_ERRORED(sbuf))) 827c478bd9Sstevel@tonic-gate 8345916cd2Sjpk #define ALLOC_CLEAN "-A" 8445916cd2Sjpk #define DEALLOC_CLEAN "-D" 8545916cd2Sjpk #define DAC_DIR "/etc/security/dev" 867c478bd9Sstevel@tonic-gate #define DEVICE_AUTH_SEPARATOR "," 8745916cd2Sjpk #define LOCALDEVICE "/dev/console" 887c478bd9Sstevel@tonic-gate #define PROCFS "/proc/" 8945916cd2Sjpk #define SFF_NO_ERROR 0x1 9045916cd2Sjpk 9145916cd2Sjpk #define ALLOC_BY_NONE -1 9245916cd2Sjpk #define CHECK_DRANGE 1 9345916cd2Sjpk #define CHECK_URANGE 2 9445916cd2Sjpk #define CHECK_ZLABEL 3 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate extern void audit_allocate_list(char *); 977c478bd9Sstevel@tonic-gate extern void audit_allocate_device(char *); 987c478bd9Sstevel@tonic-gate 9945916cd2Sjpk extern int system_labeled; 1007c478bd9Sstevel@tonic-gate extern char *newenv[]; 1017c478bd9Sstevel@tonic-gate 10245916cd2Sjpk struct state_file { 10345916cd2Sjpk int sf_flags; 10445916cd2Sjpk char sf_path[MAXPATHLEN]; 10545916cd2Sjpk }; 10645916cd2Sjpk 10745916cd2Sjpk struct file_info { 10845916cd2Sjpk struct stat fi_stat; 10945916cd2Sjpk char *fi_message; 11045916cd2Sjpk }; 11145916cd2Sjpk 11245916cd2Sjpk struct zone_path { 11345916cd2Sjpk int count; 11445916cd2Sjpk char **path; 11545916cd2Sjpk }; 11645916cd2Sjpk 117facf4a8dSllai1 struct dev_names { 11845916cd2Sjpk char **dnames; 11945916cd2Sjpk }; 12045916cd2Sjpk 12145916cd2Sjpk static int _dev_file_name(struct state_file *, devmap_t *); 122*10ddde3aSaj static int lock_dev(char *, struct stat *); 12345916cd2Sjpk static int _check_label(devalloc_t *, char *, uid_t, int); 12445916cd2Sjpk static int create_znode(char *, struct zone_path *, devmap_t *); 12545916cd2Sjpk static int remove_znode(char *, devmap_t *); 12645916cd2Sjpk static int update_device(char **, char *, int); 12745916cd2Sjpk 1287c478bd9Sstevel@tonic-gate /* 12945916cd2Sjpk * checks if the invoking user is local to the device 1307c478bd9Sstevel@tonic-gate */ 13145916cd2Sjpk /*ARGSUSED*/ 13245916cd2Sjpk int 13345916cd2Sjpk _is_local(uid_t uid) 1347c478bd9Sstevel@tonic-gate { 13545916cd2Sjpk struct stat statbuf; 1367c478bd9Sstevel@tonic-gate 13745916cd2Sjpk if (stat(LOCALDEVICE, &statbuf) == 0 && 13845916cd2Sjpk statbuf.st_uid == uid) 1397c478bd9Sstevel@tonic-gate return (1); 14045916cd2Sjpk 1417c478bd9Sstevel@tonic-gate return (0); 1427c478bd9Sstevel@tonic-gate } 1437c478bd9Sstevel@tonic-gate 14445916cd2Sjpk /* 14545916cd2Sjpk * Checks if the user with the specified uid has the specified authorization 14645916cd2Sjpk */ 14745916cd2Sjpk int 14845916cd2Sjpk _is_authorized(char *auths, uid_t uid) 1497c478bd9Sstevel@tonic-gate { 15045916cd2Sjpk char *dcp, *authlist, *lasts; 15145916cd2Sjpk char pw_buf[NSS_BUFLEN_PASSWD]; 15245916cd2Sjpk struct passwd pw_ent; 1537c478bd9Sstevel@tonic-gate 15445916cd2Sjpk /* 15545916cd2Sjpk * first, the easy cases 15645916cd2Sjpk */ 15745916cd2Sjpk if (strcmp(auths, "@") == 0) 15845916cd2Sjpk return (1); 15945916cd2Sjpk if (strcmp(auths, "*") == 0) 16045916cd2Sjpk return (ALLOC_BY_NONE); 16145916cd2Sjpk if (getpwuid_r(uid, &pw_ent, pw_buf, sizeof (pw_buf)) == NULL) 16245916cd2Sjpk return (0); 16345916cd2Sjpk if (strpbrk(auths, DEVICE_AUTH_SEPARATOR) == NULL) 16445916cd2Sjpk return (chkauthattr(auths, pw_ent.pw_name)); 16545916cd2Sjpk authlist = strdup(auths); 16645916cd2Sjpk if (authlist == NULL) 16745916cd2Sjpk return (0); 16845916cd2Sjpk for (dcp = authlist; 16945916cd2Sjpk (dcp = strtok_r(dcp, DEVICE_AUTH_SEPARATOR, &lasts)) != NULL; 17045916cd2Sjpk dcp = NULL) { 17145916cd2Sjpk if (chkauthattr(dcp, pw_ent.pw_name)) 17245916cd2Sjpk break; 17345916cd2Sjpk } 17445916cd2Sjpk free(authlist); 1757c478bd9Sstevel@tonic-gate 17645916cd2Sjpk return (dcp != NULL); 1777c478bd9Sstevel@tonic-gate } 17845916cd2Sjpk 17945916cd2Sjpk /* 18045916cd2Sjpk * Checks if the specified user has authorization for the device 18145916cd2Sjpk */ 18245916cd2Sjpk int 18345916cd2Sjpk _is_dev_authorized(devalloc_t *da, uid_t uid) 18445916cd2Sjpk { 18545916cd2Sjpk int ares; 18645916cd2Sjpk char *auth_list, *dcp, *subauth = NULL; 18745916cd2Sjpk 18845916cd2Sjpk auth_list = da->da_devauth; 18945916cd2Sjpk if (auth_list == NULL) 19045916cd2Sjpk return (0); 19145916cd2Sjpk dcp = strpbrk(auth_list, KV_TOKEN_DELIMIT); 19245916cd2Sjpk if (dcp == NULL) 19345916cd2Sjpk return (_is_authorized(auth_list, uid)); 19445916cd2Sjpk if (_is_local(uid)) { 19545916cd2Sjpk /* the local authorization is before the separator */ 19645916cd2Sjpk ares = dcp - auth_list; 19745916cd2Sjpk subauth = malloc(ares + 1); 19845916cd2Sjpk if (subauth == NULL) 19945916cd2Sjpk return (0); 20045916cd2Sjpk (void) strlcpy(subauth, auth_list, (ares + 1)); 20145916cd2Sjpk auth_list = subauth; 20245916cd2Sjpk } else 20345916cd2Sjpk auth_list = dcp + 1; 20445916cd2Sjpk ares = _is_authorized(auth_list, uid); 20545916cd2Sjpk if (subauth != NULL) 20645916cd2Sjpk free(subauth); 20745916cd2Sjpk 20845916cd2Sjpk return (ares); 2097c478bd9Sstevel@tonic-gate } 21045916cd2Sjpk 21145916cd2Sjpk int 21245916cd2Sjpk check_devs(devmap_t *dm) 21345916cd2Sjpk { 21445916cd2Sjpk int status = 0; 21545916cd2Sjpk char **file; 21645916cd2Sjpk 21745916cd2Sjpk if (dm->dmap_devarray == NULL) 21845916cd2Sjpk return (NODMAPERR); 21945916cd2Sjpk for (file = dm->dmap_devarray; *file != NULL; file++) { 22045916cd2Sjpk if ((status = access(*file, F_OK)) == -1) { 22145916cd2Sjpk dprintf("Unable to access file %s\n", *file); 22245916cd2Sjpk break; 22345916cd2Sjpk } 22445916cd2Sjpk } 22545916cd2Sjpk 22645916cd2Sjpk return (status); 22745916cd2Sjpk } 22845916cd2Sjpk 22945916cd2Sjpk int 23045916cd2Sjpk print_da_defs(da_defs_t *da_defs) 23145916cd2Sjpk { 23245916cd2Sjpk char optbuf[BUFSIZ]; 23345916cd2Sjpk char *p = NULL; 23445916cd2Sjpk 23545916cd2Sjpk if (da_defs->devopts == NULL) { 23645916cd2Sjpk dprintf("No default attributes for %s\n", da_defs->devtype); 23745916cd2Sjpk return (DEFATTRSERR); 23845916cd2Sjpk } 23945916cd2Sjpk (void) printf("dev_type=%s\n", da_defs->devtype); 24045916cd2Sjpk if (_kva2str(da_defs->devopts, optbuf, sizeof (optbuf), KV_ASSIGN, 24145916cd2Sjpk KV_TOKEN_DELIMIT) == 0) { 24245916cd2Sjpk if (p = rindex(optbuf, ':')) 24345916cd2Sjpk *p = '\0'; 24445916cd2Sjpk (void) printf("\t%s\n", optbuf); 24545916cd2Sjpk } 24645916cd2Sjpk 2477c478bd9Sstevel@tonic-gate return (0); 2487c478bd9Sstevel@tonic-gate } 2497c478bd9Sstevel@tonic-gate 25045916cd2Sjpk void 25145916cd2Sjpk print_dev_attrs(int optflag, devalloc_t *da, devmap_t *dm, 25245916cd2Sjpk struct file_info *fip) 2537c478bd9Sstevel@tonic-gate { 25445916cd2Sjpk char *p = NULL; 25545916cd2Sjpk char optbuf[BUFSIZ]; 2567c478bd9Sstevel@tonic-gate 25745916cd2Sjpk (void) printf("device=%s%s", dm->dmap_devname, KV_DELIMITER); 25845916cd2Sjpk (void) printf("type=%s%s", dm->dmap_devtype, KV_DELIMITER); 25945916cd2Sjpk (void) printf("auths=%s%s", 26045916cd2Sjpk (da->da_devauth ? da->da_devauth : ""), KV_DELIMITER); 26145916cd2Sjpk (void) printf("clean=%s%s", 26245916cd2Sjpk (da->da_devexec ? da->da_devexec : ""), KV_DELIMITER); 26345916cd2Sjpk if (da->da_devopts != NULL) { 26445916cd2Sjpk if (_kva2str(da->da_devopts, optbuf, sizeof (optbuf), 26545916cd2Sjpk KV_ASSIGN, KV_TOKEN_DELIMIT) == 0) { 26645916cd2Sjpk if (p = rindex(optbuf, ':')) 26745916cd2Sjpk *p = '\0'; 26845916cd2Sjpk (void) printf("%s", optbuf); 26945916cd2Sjpk } 27045916cd2Sjpk } 27145916cd2Sjpk (void) printf("%s", KV_DELIMITER); 27245916cd2Sjpk if (optflag & WINDOWING) { 273*10ddde3aSaj if ((fip->fi_message != NULL) && 274*10ddde3aSaj (strcmp(fip->fi_message, DAOPT_CLASS) == 0)) 275*10ddde3aSaj (void) printf("owner=/FREE%s", KV_DELIMITER); 27645916cd2Sjpk else if (DEV_ERRORED(fip->fi_stat)) 27745916cd2Sjpk (void) printf("owner=/ERROR%s", KV_DELIMITER); 27845916cd2Sjpk else if (!DEV_ALLOCATED(fip->fi_stat)) 27945916cd2Sjpk (void) printf("owner=/FREE%s", KV_DELIMITER); 28045916cd2Sjpk else 281f48205beScasper (void) printf("owner=%u%s", fip->fi_stat.st_uid, 28245916cd2Sjpk KV_DELIMITER); 28345916cd2Sjpk } 28445916cd2Sjpk (void) printf("files=%s", dm->dmap_devlist); 28545916cd2Sjpk (void) printf("\n"); 28645916cd2Sjpk } 28745916cd2Sjpk 28845916cd2Sjpk void 28945916cd2Sjpk print_dev(devmap_t *dm) 29045916cd2Sjpk { 29145916cd2Sjpk char **file; 29245916cd2Sjpk 29345916cd2Sjpk (void) printf(gettext("device: %s "), dm->dmap_devname); 29445916cd2Sjpk (void) printf(gettext("type: %s "), dm->dmap_devtype); 2957c478bd9Sstevel@tonic-gate (void) printf(gettext("files:")); 29645916cd2Sjpk file = dm->dmap_devarray; 29745916cd2Sjpk if (file != NULL) { 29845916cd2Sjpk for (; *file != NULL; file++) 29945916cd2Sjpk (void) printf(" %s", *file); 3007c478bd9Sstevel@tonic-gate } 3017c478bd9Sstevel@tonic-gate (void) printf("\n"); 3027c478bd9Sstevel@tonic-gate } 3037c478bd9Sstevel@tonic-gate 30445916cd2Sjpk /* ARGSUSED */ 30545916cd2Sjpk int 30645916cd2Sjpk _list_device(int optflag, uid_t uid, devalloc_t *da, char *zonename) 3077c478bd9Sstevel@tonic-gate { 30845916cd2Sjpk int bytes = 0; 30945916cd2Sjpk int error = 0; 31045916cd2Sjpk int is_authorized = 0; 31145916cd2Sjpk char *fname = NULL; 3127c478bd9Sstevel@tonic-gate char file_name[MAXPATHLEN]; 31345916cd2Sjpk devmap_t *dm; 31445916cd2Sjpk struct file_info fi; 31545916cd2Sjpk struct state_file sf; 3167c478bd9Sstevel@tonic-gate 317*10ddde3aSaj fi.fi_message = NULL; 31845916cd2Sjpk setdmapent(); 31945916cd2Sjpk if ((dm = getdmapnam(da->da_devname)) == NULL) { 32045916cd2Sjpk enddmapent(); 32145916cd2Sjpk dprintf("Unable to find %s in the maps database\n", 32245916cd2Sjpk da->da_devname); 32345916cd2Sjpk return (NODMAPERR); 3247c478bd9Sstevel@tonic-gate } 32545916cd2Sjpk enddmapent(); 326*10ddde3aSaj 327*10ddde3aSaj if ((optflag & CLASS) && 328*10ddde3aSaj (!(optflag & (LISTALL | LISTFREE | LISTALLOC)))) { 329*10ddde3aSaj fi.fi_message = DAOPT_CLASS; 330*10ddde3aSaj if (optflag & LISTATTRS) 331*10ddde3aSaj print_dev_attrs(optflag, da, dm, &fi); 332*10ddde3aSaj else 333*10ddde3aSaj print_dev(dm); 334*10ddde3aSaj goto out; 335*10ddde3aSaj } 336*10ddde3aSaj 33745916cd2Sjpk if (system_labeled) { 33845916cd2Sjpk if ((error = _dev_file_name(&sf, dm)) != 0) { 33945916cd2Sjpk freedmapent(dm); 34045916cd2Sjpk dprintf("Unable to find %s device files\n", 34145916cd2Sjpk da->da_devname); 34245916cd2Sjpk error = NODMAPERR; 34345916cd2Sjpk goto out; 3447c478bd9Sstevel@tonic-gate } 34545916cd2Sjpk fname = sf.sf_path; 34645916cd2Sjpk } else { 34745916cd2Sjpk bytes = snprintf(file_name, MAXPATHLEN, "%s/%s", DAC_DIR, 34845916cd2Sjpk da->da_devname); 34945916cd2Sjpk if (bytes <= 0) { 35045916cd2Sjpk error = DEVNAMEERR; 35145916cd2Sjpk goto out; 35245916cd2Sjpk } else if (bytes >= MAXPATHLEN) { 35345916cd2Sjpk dprintf("device name %s is too long.\n", 35445916cd2Sjpk da->da_devname); 35545916cd2Sjpk error = DEVLONGERR; 35645916cd2Sjpk goto out; 3577c478bd9Sstevel@tonic-gate } 35845916cd2Sjpk fname = file_name; 35945916cd2Sjpk } 36045916cd2Sjpk if (stat(fname, &fi.fi_stat) != 0) { 36145916cd2Sjpk dprintf("Unable to stat %s\n", fname); 3627c478bd9Sstevel@tonic-gate dperror("Error:"); 36345916cd2Sjpk error = DACACCERR; 36445916cd2Sjpk goto out; 36545916cd2Sjpk } 36645916cd2Sjpk if (optflag & USERID) 36745916cd2Sjpk is_authorized = 1; 36845916cd2Sjpk else 36945916cd2Sjpk is_authorized = _is_dev_authorized(da, uid); 37045916cd2Sjpk if (optflag & LISTFREE) { /* list_devices -n */ 37145916cd2Sjpk /* 37245916cd2Sjpk * list all free devices 37345916cd2Sjpk */ 37445916cd2Sjpk if (DEV_ALLOCATED(fi.fi_stat)) { 37545916cd2Sjpk error = PREALLOCERR; 37645916cd2Sjpk goto out; 37745916cd2Sjpk } 37845916cd2Sjpk if (system_labeled) { 37945916cd2Sjpk /* 38045916cd2Sjpk * for this free device, check if - 38145916cd2Sjpk * 1. user has authorization to allocate 38245916cd2Sjpk * 2. the zone label is within the label range of the 38345916cd2Sjpk * device 38445916cd2Sjpk */ 38545916cd2Sjpk if (is_authorized == ALLOC_BY_NONE) { 38645916cd2Sjpk error = DAUTHERR; 38745916cd2Sjpk goto out; 38845916cd2Sjpk } else if (is_authorized == 0) { 38945916cd2Sjpk error = UAUTHERR; 39045916cd2Sjpk goto out; 39145916cd2Sjpk } 39245916cd2Sjpk if (_check_label(da, zonename, uid, 39345916cd2Sjpk CHECK_DRANGE) != 0) { 39445916cd2Sjpk error = LABELRNGERR; 39545916cd2Sjpk goto out; 39645916cd2Sjpk } 39745916cd2Sjpk } 39845916cd2Sjpk } else if (optflag & LISTALLOC) { /* list_devices -u */ 39945916cd2Sjpk /* 40045916cd2Sjpk * list all allocated devices 40145916cd2Sjpk */ 40245916cd2Sjpk if (!DEV_ALLOCATED(fi.fi_stat)) { 40345916cd2Sjpk error = DEVNALLOCERR; 40445916cd2Sjpk goto out; 40545916cd2Sjpk } 40645916cd2Sjpk if (fi.fi_stat.st_uid != uid) { 40745916cd2Sjpk error = DEVSTATEERR; 40845916cd2Sjpk goto out; 40945916cd2Sjpk } 41045916cd2Sjpk if (system_labeled) { 41145916cd2Sjpk /* 41245916cd2Sjpk * check if the zone label equals the label at which 41345916cd2Sjpk * the device is allocated. 41445916cd2Sjpk */ 41545916cd2Sjpk if (_check_label(da, zonename, uid, 41645916cd2Sjpk CHECK_ZLABEL) != 0) { 41745916cd2Sjpk error = LABELRNGERR; 41845916cd2Sjpk goto out; 41945916cd2Sjpk } 42045916cd2Sjpk } 42145916cd2Sjpk } else if (optflag & LISTALL) { /* list_devices -l */ 42245916cd2Sjpk /* 42345916cd2Sjpk * list all devices - free and allocated - available 42445916cd2Sjpk */ 42545916cd2Sjpk if (DEV_ALLOCATED(fi.fi_stat)) { 42645916cd2Sjpk if (optflag & WINDOWING && 42745916cd2Sjpk (is_authorized == ALLOC_BY_NONE)) { 42845916cd2Sjpk /* 42945916cd2Sjpk * don't complain if we're here for the GUI. 43045916cd2Sjpk */ 43145916cd2Sjpk error = 0; 43245916cd2Sjpk } else if (fi.fi_stat.st_uid != uid) { 43345916cd2Sjpk if (!(optflag & WINDOWING)) { 43445916cd2Sjpk error = ALLOCUERR; 43545916cd2Sjpk goto out; 43645916cd2Sjpk } 43745916cd2Sjpk } 43845916cd2Sjpk if (system_labeled && !(optflag & WINDOWING)) { 43945916cd2Sjpk /* 44045916cd2Sjpk * if we're not displaying in the GUI, 44145916cd2Sjpk * check if the zone label equals the label 44245916cd2Sjpk * at which the device is allocated. 44345916cd2Sjpk */ 44445916cd2Sjpk if (_check_label(da, zonename, uid, 44545916cd2Sjpk CHECK_ZLABEL) != 0) { 44645916cd2Sjpk error = LABELRNGERR; 44745916cd2Sjpk goto out; 44845916cd2Sjpk } 44945916cd2Sjpk } 45045916cd2Sjpk } else if (system_labeled && !(optflag & WINDOWING)) { 45145916cd2Sjpk /* 45245916cd2Sjpk * if we're not displaying in the GUI, 45345916cd2Sjpk * for this free device, check if - 45445916cd2Sjpk * 1. user has authorization to allocate 45545916cd2Sjpk * 2. the zone label is within the label range of the 45645916cd2Sjpk * device 45745916cd2Sjpk */ 45845916cd2Sjpk if (is_authorized == ALLOC_BY_NONE) { 45945916cd2Sjpk error = DAUTHERR; 46045916cd2Sjpk goto out; 46145916cd2Sjpk } else if (is_authorized == 0) { 46245916cd2Sjpk error = UAUTHERR; 46345916cd2Sjpk goto out; 46445916cd2Sjpk } 46545916cd2Sjpk if (_check_label(da, zonename, uid, 46645916cd2Sjpk CHECK_DRANGE) != 0) { 46745916cd2Sjpk error = LABELRNGERR; 46845916cd2Sjpk goto out; 46945916cd2Sjpk } 47045916cd2Sjpk } 47145916cd2Sjpk } 47245916cd2Sjpk if (system_labeled && DEV_ERRORED(fi.fi_stat) && !(optflag & LISTALL)) { 47345916cd2Sjpk error = DEVSTATEERR; 47445916cd2Sjpk goto out; 47545916cd2Sjpk } 47645916cd2Sjpk if (check_devs(dm) == -1) { 47745916cd2Sjpk error = DSPMISSERR; 47845916cd2Sjpk goto out; 47945916cd2Sjpk } 48045916cd2Sjpk if (optflag & LISTATTRS) 48145916cd2Sjpk print_dev_attrs(optflag, da, dm, &fi); 48245916cd2Sjpk else 48345916cd2Sjpk print_dev(dm); 48445916cd2Sjpk 48545916cd2Sjpk error = 0; 48645916cd2Sjpk 48745916cd2Sjpk out: 48845916cd2Sjpk freedmapent(dm); 48945916cd2Sjpk return (error); 4907c478bd9Sstevel@tonic-gate } 4917c478bd9Sstevel@tonic-gate 49245916cd2Sjpk /* ARGSUSED */ 49345916cd2Sjpk int 49445916cd2Sjpk list_devices(int optflag, uid_t uid, char *device, char *zonename) 49545916cd2Sjpk { 49645916cd2Sjpk int error = 0; 497*10ddde3aSaj char *class = NULL; 49845916cd2Sjpk da_defs_t *da_defs; 49945916cd2Sjpk devalloc_t *da; 5007c478bd9Sstevel@tonic-gate 50145916cd2Sjpk if (system_labeled && optflag & WINDOWING && !(optflag & LISTATTRS)) { 50245916cd2Sjpk /* 50345916cd2Sjpk * Private interface for GUI. 50445916cd2Sjpk */ 50545916cd2Sjpk (void) puts(DA_DB_LOCK); 5067c478bd9Sstevel@tonic-gate return (0); 5077c478bd9Sstevel@tonic-gate } 50845916cd2Sjpk if (optflag & USERID) { 50945916cd2Sjpk /* 51045916cd2Sjpk * we need device.revoke to list someone else's devices 51145916cd2Sjpk */ 51245916cd2Sjpk if (!_is_authorized(DEVICE_REVOKE_AUTH, getuid())) 51345916cd2Sjpk return (UAUTHERR); 51445916cd2Sjpk } 51545916cd2Sjpk if (system_labeled) { 51645916cd2Sjpk if (!(optflag & USERID) && 51745916cd2Sjpk !_is_authorized(DEFAULT_DEV_ALLOC_AUTH, uid)) 51845916cd2Sjpk /* 51945916cd2Sjpk * we need device.allocate to list our devices 52045916cd2Sjpk */ 52145916cd2Sjpk return (UAUTHERR); 52245916cd2Sjpk if (optflag & LISTDEFS) { 52345916cd2Sjpk /* 52445916cd2Sjpk * list default attrs from devalloc_defaults 52545916cd2Sjpk */ 52645916cd2Sjpk setdadefent(); 52745916cd2Sjpk if (device) { 52845916cd2Sjpk /* 52945916cd2Sjpk * list default attrs for this device type 53045916cd2Sjpk */ 53145916cd2Sjpk da_defs = getdadeftype(device); 53245916cd2Sjpk if (da_defs == NULL) { 53345916cd2Sjpk enddadefent(); 53445916cd2Sjpk dprintf("No default attributes for " 53545916cd2Sjpk "%s\n", device); 53645916cd2Sjpk return (DEFATTRSERR); 53745916cd2Sjpk } 53845916cd2Sjpk error = print_da_defs(da_defs); 53945916cd2Sjpk freedadefent(da_defs); 54045916cd2Sjpk } else { 54145916cd2Sjpk /* 54245916cd2Sjpk * list everything in devalloc_defaults 54345916cd2Sjpk */ 54445916cd2Sjpk while ((da_defs = getdadefent()) != NULL) { 54545916cd2Sjpk (void) print_da_defs(da_defs); 54645916cd2Sjpk freedadefent(da_defs); 54745916cd2Sjpk } 54845916cd2Sjpk } 54945916cd2Sjpk enddadefent(); 55045916cd2Sjpk return (error); 55145916cd2Sjpk } 5527c478bd9Sstevel@tonic-gate } 553*10ddde3aSaj /* 554*10ddde3aSaj * Lock the database to make sure no body writes to it while we are 555*10ddde3aSaj * reading. 556*10ddde3aSaj */ 557*10ddde3aSaj (void) lock_dev(NULL, NULL); 5587c478bd9Sstevel@tonic-gate setdaent(); 5597c478bd9Sstevel@tonic-gate if (device) { 560*10ddde3aSaj if (optflag & CLASS) { 561*10ddde3aSaj /* 562*10ddde3aSaj * list all devices of this class. 563*10ddde3aSaj */ 564*10ddde3aSaj while ((da = getdaent()) != NULL) { 565*10ddde3aSaj class = kva_match(da->da_devopts, DAOPT_CLASS); 566*10ddde3aSaj if (class && (strcmp(class, device) == 0)) { 567*10ddde3aSaj (void) _list_device(optflag, uid, da, 568*10ddde3aSaj zonename); 569*10ddde3aSaj } 570*10ddde3aSaj freedaent(da); 571*10ddde3aSaj } 572*10ddde3aSaj } else { 57345916cd2Sjpk /* 57445916cd2Sjpk * list this device 57545916cd2Sjpk */ 57645916cd2Sjpk if ((da = getdanam(device)) == NULL) { 5777c478bd9Sstevel@tonic-gate enddaent(); 57845916cd2Sjpk return (NODAERR); 57945916cd2Sjpk } 58045916cd2Sjpk error = _list_device(optflag, uid, da, zonename); 58145916cd2Sjpk freedaent(da); 582*10ddde3aSaj } 58345916cd2Sjpk } else { 58445916cd2Sjpk /* 58545916cd2Sjpk * list all devices 58645916cd2Sjpk */ 58745916cd2Sjpk while ((da = getdaent()) != NULL) { 58845916cd2Sjpk (void) _list_device(optflag, uid, da, zonename); 58945916cd2Sjpk freedaent(da); 59045916cd2Sjpk } 59145916cd2Sjpk } 59245916cd2Sjpk enddaent(); 59345916cd2Sjpk 59445916cd2Sjpk return (error); 5957c478bd9Sstevel@tonic-gate } 5967c478bd9Sstevel@tonic-gate 5977c478bd9Sstevel@tonic-gate /* 5987c478bd9Sstevel@tonic-gate * Set the DAC characteristics of the file. 5997c478bd9Sstevel@tonic-gate * This uses a fancy chmod() by setting a minimal ACL which sets the mode 6007c478bd9Sstevel@tonic-gate * and discards any existing ACL. 6017c478bd9Sstevel@tonic-gate */ 60245916cd2Sjpk int 60345916cd2Sjpk _newdac(char *file, uid_t owner, gid_t group, o_mode_t mode) 6047c478bd9Sstevel@tonic-gate { 6057c478bd9Sstevel@tonic-gate int err = 0; 6067c478bd9Sstevel@tonic-gate 60745916cd2Sjpk if (mode == ALLOC_MODE) { 6087c478bd9Sstevel@tonic-gate if (chown(file, owner, group) == -1) { 60945916cd2Sjpk dperror("newdac: unable to chown"); 61045916cd2Sjpk err = CHOWNERR; 61145916cd2Sjpk } 61245916cd2Sjpk } else do { 61345916cd2Sjpk if (chown(file, owner, group) == -1) { 61445916cd2Sjpk dperror("newdac: unable to chown"); 61545916cd2Sjpk err = CHOWNERR; 6167c478bd9Sstevel@tonic-gate } 6177c478bd9Sstevel@tonic-gate } while (fdetach(file) == 0); 6187c478bd9Sstevel@tonic-gate 61945916cd2Sjpk if (err) 62045916cd2Sjpk return (err); 62145916cd2Sjpk 62245916cd2Sjpk if (strncmp(file, "/dev/", strlen("/dev/")) != 0) { 62345916cd2Sjpk /* 62445916cd2Sjpk * This could be a SunRay device that is in /tmp. 62545916cd2Sjpk */ 62645916cd2Sjpk if (chmod(file, mode) == -1) { 62745916cd2Sjpk dperror("newdac: unable to chmod"); 62845916cd2Sjpk err = SETACLERR; 62945916cd2Sjpk } 63045916cd2Sjpk } else { 631fa9e4066Sahrens err = acl_strip(file, owner, group, (mode_t)mode); 63245916cd2Sjpk } 633fa9e4066Sahrens 634fa9e4066Sahrens if (err != 0) { 63545916cd2Sjpk dperror("newdac: unable to setacl"); 63645916cd2Sjpk err = SETACLERR; 6377c478bd9Sstevel@tonic-gate } 6387c478bd9Sstevel@tonic-gate 6397c478bd9Sstevel@tonic-gate return (err); 6407c478bd9Sstevel@tonic-gate } 6417c478bd9Sstevel@tonic-gate 642*10ddde3aSaj /* 643*10ddde3aSaj * lock_dev - 644*10ddde3aSaj * locks a section of DA_DB_LOCK. 645*10ddde3aSaj * returns lock fd if successful, else -1 on error. 646*10ddde3aSaj */ 6477c478bd9Sstevel@tonic-gate static int 648*10ddde3aSaj lock_dev(char *file, struct stat *statbuf) 6497c478bd9Sstevel@tonic-gate { 650*10ddde3aSaj static int lockfd = -1; 651*10ddde3aSaj int ret; 652*10ddde3aSaj int count = 0; 653*10ddde3aSaj int retry = 10; 654*10ddde3aSaj off_t size = 0; 655*10ddde3aSaj off_t offset; 656*10ddde3aSaj char *lockfile; 6577c478bd9Sstevel@tonic-gate 658*10ddde3aSaj if (system_labeled) 659*10ddde3aSaj lockfile = DA_DB_LOCK; 660*10ddde3aSaj else 661*10ddde3aSaj lockfile = file; 662*10ddde3aSaj 663*10ddde3aSaj if (statbuf) { 664*10ddde3aSaj offset = statbuf->st_rdev; 6657c478bd9Sstevel@tonic-gate dprintf("locking %s\n", file); 666*10ddde3aSaj } else { 667*10ddde3aSaj offset = 0; 668*10ddde3aSaj dprintf("locking %s\n", lockfile); 6697c478bd9Sstevel@tonic-gate } 670*10ddde3aSaj if ((lockfd == -1) && 671*10ddde3aSaj (lockfd = open(lockfile, O_RDWR | O_CREAT, 0600)) == -1) { 672*10ddde3aSaj dperror("lock_dev: cannot open lock file"); 673*10ddde3aSaj return (-1); 674*10ddde3aSaj } 675*10ddde3aSaj if (system_labeled) { 676*10ddde3aSaj (void) _newdac(lockfile, DA_UID, DA_GID, 0600); 677*10ddde3aSaj if (lseek(lockfd, offset, SEEK_SET) == -1) { 678*10ddde3aSaj dperror("lock_dev: cannot position lock file"); 679*10ddde3aSaj return (-1); 680*10ddde3aSaj } 681*10ddde3aSaj size = 1; 682*10ddde3aSaj } 683*10ddde3aSaj errno = 0; 684*10ddde3aSaj while (retry) { 685*10ddde3aSaj count++; 686*10ddde3aSaj ret = lockf(lockfd, F_TLOCK, size); 687*10ddde3aSaj if (ret == 0) 688*10ddde3aSaj return (lockfd); 689*10ddde3aSaj if ((errno != EACCES) && (errno != EAGAIN)) { 69045916cd2Sjpk dperror("lock_dev: cannot set lock"); 691*10ddde3aSaj return (-1); 692*10ddde3aSaj } 693*10ddde3aSaj retry--; 694*10ddde3aSaj (void) sleep(count); 695*10ddde3aSaj errno = 0; 6967c478bd9Sstevel@tonic-gate } 6977c478bd9Sstevel@tonic-gate 698*10ddde3aSaj return (-1); 6997c478bd9Sstevel@tonic-gate } 7007c478bd9Sstevel@tonic-gate 70145916cd2Sjpk int 70245916cd2Sjpk mk_alloc(devmap_t *list, uid_t uid, struct zone_path *zpath) 7037c478bd9Sstevel@tonic-gate { 70445916cd2Sjpk int i; 70545916cd2Sjpk int error = 0; 70645916cd2Sjpk char **file; 70745916cd2Sjpk gid_t gid = getgid(); 70845916cd2Sjpk mode_t mode = ALLOC_MODE; 7097c478bd9Sstevel@tonic-gate 71045916cd2Sjpk file = list->dmap_devarray; 71145916cd2Sjpk if (file == NULL) 71245916cd2Sjpk return (NODMAPERR); 71345916cd2Sjpk for (; *file != NULL; file++) { 71445916cd2Sjpk dprintf("Allocating %s\n", *file); 71545916cd2Sjpk if ((error = _newdac(*file, uid, gid, mode)) != 0) { 716*10ddde3aSaj (void) _newdac(*file, ALLOC_ERRID, DA_GID, 7177c478bd9Sstevel@tonic-gate ALLOC_ERR_MODE); 71845916cd2Sjpk break; 71945916cd2Sjpk } 72045916cd2Sjpk } 72145916cd2Sjpk if (system_labeled && zpath->count && (error == 0)) { 72245916cd2Sjpk /* 72345916cd2Sjpk * mark as allocated any new device nodes that we 72445916cd2Sjpk * created in local zone 72545916cd2Sjpk */ 72645916cd2Sjpk for (i = 0; i < zpath->count; i++) { 72745916cd2Sjpk dprintf("Allocating %s\n", zpath->path[i]); 72845916cd2Sjpk if ((error = _newdac(zpath->path[i], uid, gid, 72945916cd2Sjpk mode)) != 0) { 73045916cd2Sjpk (void) _newdac(zpath->path[i], ALLOC_ERRID, 731*10ddde3aSaj DA_GID, ALLOC_ERR_MODE); 73245916cd2Sjpk break; 73345916cd2Sjpk } 73445916cd2Sjpk } 7357c478bd9Sstevel@tonic-gate } 7367c478bd9Sstevel@tonic-gate 73745916cd2Sjpk return (error); 7387c478bd9Sstevel@tonic-gate } 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate /* 7417c478bd9Sstevel@tonic-gate * mk_revoke() is used instead of system("/usr/sbin/fuser -k file") 7427c478bd9Sstevel@tonic-gate * because "/usr/sbin/fuser -k file" kills all processes 7437c478bd9Sstevel@tonic-gate * working with the file, even "vold" (bug #4095152). 7447c478bd9Sstevel@tonic-gate */ 74545916cd2Sjpk int 74645916cd2Sjpk mk_revoke(int optflag, char *file) 7477c478bd9Sstevel@tonic-gate { 7487c478bd9Sstevel@tonic-gate int r = 0, p[2], fp, lock; 74945916cd2Sjpk int fuserpid; 75045916cd2Sjpk char buf[MAXPATHLEN]; 7517c478bd9Sstevel@tonic-gate FILE *ptr; 75245916cd2Sjpk pid_t c_pid; 7537c478bd9Sstevel@tonic-gate prpsinfo_t info; 7547c478bd9Sstevel@tonic-gate 7557c478bd9Sstevel@tonic-gate (void) strcpy(buf, PROCFS); 7567c478bd9Sstevel@tonic-gate /* 75745916cd2Sjpk * vfork() and execl() just to make the same output 7587c478bd9Sstevel@tonic-gate * as before fixing of bug #4095152. 7597c478bd9Sstevel@tonic-gate * The problem is that the "fuser" command prints 7607c478bd9Sstevel@tonic-gate * one part of output into stderr and another into stdout, 7617c478bd9Sstevel@tonic-gate * but user sees them mixed. Of course, better to change "fuser" 7627c478bd9Sstevel@tonic-gate * or to intercept and not to print its output. 7637c478bd9Sstevel@tonic-gate */ 76445916cd2Sjpk if (!(optflag & SILENT)) { 7657c478bd9Sstevel@tonic-gate c_pid = vfork(); 7667c478bd9Sstevel@tonic-gate if (c_pid == -1) 7677c478bd9Sstevel@tonic-gate return (-1); 7687c478bd9Sstevel@tonic-gate if (c_pid == 0) { 7697c478bd9Sstevel@tonic-gate dprintf("first exec fuser %s\n", file); 77045916cd2Sjpk (void) execl("/usr/sbin/fuser", "fuser", file, NULL); 7717c478bd9Sstevel@tonic-gate dperror("first exec fuser"); 7727c478bd9Sstevel@tonic-gate _exit(1); 7737c478bd9Sstevel@tonic-gate } 7747c478bd9Sstevel@tonic-gate 7757c478bd9Sstevel@tonic-gate (void) waitpid(c_pid, &lock, 0); 7767c478bd9Sstevel@tonic-gate dprintf("exit status %x\n", lock); 7777c478bd9Sstevel@tonic-gate if (WEXITSTATUS(lock) != 0) 7787c478bd9Sstevel@tonic-gate return (-1); 7797c478bd9Sstevel@tonic-gate } 78045916cd2Sjpk dprintf("first continuing c_pid=%d\n", (int)c_pid); 7817c478bd9Sstevel@tonic-gate if (pipe(p)) { 7827c478bd9Sstevel@tonic-gate dperror("pipe"); 7837c478bd9Sstevel@tonic-gate return (-1); 7847c478bd9Sstevel@tonic-gate } 78545916cd2Sjpk /* vfork() and execl() to catch output and to process it */ 7867c478bd9Sstevel@tonic-gate c_pid = vfork(); 7877c478bd9Sstevel@tonic-gate if (c_pid == -1) { 7887c478bd9Sstevel@tonic-gate dperror("second vfork"); 7897c478bd9Sstevel@tonic-gate return (-1); 7907c478bd9Sstevel@tonic-gate } 79145916cd2Sjpk dprintf("second continuing c_pid=%d\n", (int)c_pid); 7927c478bd9Sstevel@tonic-gate if (c_pid == 0) { 7937c478bd9Sstevel@tonic-gate (void) close(p[0]); 7947c478bd9Sstevel@tonic-gate (void) close(1); 7957c478bd9Sstevel@tonic-gate (void) fcntl(p[1], F_DUPFD, 1); 7967c478bd9Sstevel@tonic-gate (void) close(p[1]); 7977c478bd9Sstevel@tonic-gate (void) close(2); 7987c478bd9Sstevel@tonic-gate dprintf("second exec fuser %s\n", file); 79945916cd2Sjpk (void) execl("/usr/sbin/fuser", "fuser", file, NULL); 8007c478bd9Sstevel@tonic-gate dperror("second exec fuser"); 8017c478bd9Sstevel@tonic-gate _exit(1); 8027c478bd9Sstevel@tonic-gate } 8037c478bd9Sstevel@tonic-gate (void) close(p[1]); 8047c478bd9Sstevel@tonic-gate if ((ptr = fdopen(p[0], "r")) != NULL) { 8057c478bd9Sstevel@tonic-gate while (!feof(ptr)) { 80645916cd2Sjpk if (fscanf(ptr, "%d", &fuserpid) > 0) { 80745916cd2Sjpk (void) sprintf(buf + strlen(PROCFS), "%d", 80845916cd2Sjpk fuserpid); 8097c478bd9Sstevel@tonic-gate if ((fp = open(buf, O_RDONLY)) == -1) { 8107c478bd9Sstevel@tonic-gate dperror(buf); 8117c478bd9Sstevel@tonic-gate continue; 8127c478bd9Sstevel@tonic-gate } 81345916cd2Sjpk if (ioctl(fp, PIOCPSINFO, 81445916cd2Sjpk (char *)&info) == -1) { 81545916cd2Sjpk dprintf("%d psinfo failed", fuserpid); 8167c478bd9Sstevel@tonic-gate dperror(""); 8177c478bd9Sstevel@tonic-gate (void) close(fp); 8187c478bd9Sstevel@tonic-gate continue; 8197c478bd9Sstevel@tonic-gate } 8207c478bd9Sstevel@tonic-gate (void) close(fp); 8217c478bd9Sstevel@tonic-gate if (strcmp(info.pr_fname, "vold") == NULL) { 82245916cd2Sjpk dprintf("%d matched vold name\n", 82345916cd2Sjpk fuserpid); 8247c478bd9Sstevel@tonic-gate continue; 8257c478bd9Sstevel@tonic-gate } 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 } 863*10ddde3aSaj 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); 884*10ddde3aSaj 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, 1000*10ddde3aSaj 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); 105945916cd2Sjpk if (!(optflag & (FORCE | FORCE_ALL)) && !is_authorized) { 106045916cd2Sjpk dprintf("User %d is unauthorized to deallocate\n", (int)uid); 106145916cd2Sjpk error = UAUTHERR; 106245916cd2Sjpk goto out; 106345916cd2Sjpk } 106445916cd2Sjpk if (system_labeled) { 106545916cd2Sjpk /* 106645916cd2Sjpk * unless we're here to deallocate by force, check if the 106745916cd2Sjpk * label at which the device is currently allocated is 106845916cd2Sjpk * within the user label range. 106945916cd2Sjpk */ 107045916cd2Sjpk if (!(optflag & FORCE) && 107145916cd2Sjpk _check_label(da, zonename, uid, CHECK_URANGE) != 0) { 107245916cd2Sjpk error = LABELRNGERR; 107345916cd2Sjpk goto out; 107445916cd2Sjpk } 107545916cd2Sjpk } 107645916cd2Sjpk if (!(optflag & FORCE) && stat_buf.st_uid != uid && 107745916cd2Sjpk DEV_ALLOCATED(stat_buf)) { 107845916cd2Sjpk error = ALLOCUERR; 107945916cd2Sjpk goto out; 108045916cd2Sjpk } 108145916cd2Sjpk if (!DEV_ALLOCATED(stat_buf)) { 108245916cd2Sjpk if (DEV_ERRORED(stat_buf)) { 108345916cd2Sjpk if (!(optflag & FORCE)) { 108445916cd2Sjpk error = DEVSTATEERR; 108545916cd2Sjpk goto out; 108645916cd2Sjpk } 108745916cd2Sjpk } else { 108845916cd2Sjpk error = DEVNALLOCERR; 108945916cd2Sjpk goto out; 109045916cd2Sjpk } 109145916cd2Sjpk } 109245916cd2Sjpk /* All checks passed, time to lock and deallocate */ 1093*10ddde3aSaj if ((*lock_fd = lock_dev(fname, &stat_buf)) == -1) { 1094*10ddde3aSaj error = DEVLKERR; 109545916cd2Sjpk goto out; 1096*10ddde3aSaj } 109745916cd2Sjpk if (system_labeled) { 109845916cd2Sjpk devzone = kva_match(da->da_devopts, DAOPT_ZONE); 1099*10ddde3aSaj if (devzone == NULL) { 1100*10ddde3aSaj devzone = GLOBAL_ZONENAME; 1101*10ddde3aSaj } else if (strcmp(devzone, GLOBAL_ZONENAME) != 0) { 110245916cd2Sjpk if ((remove_znode(devzone, dm) != 0) && 110345916cd2Sjpk !(optflag & FORCE)) { 110445916cd2Sjpk error = ZONEERR; 110545916cd2Sjpk goto out; 110645916cd2Sjpk } 110745916cd2Sjpk } 110845916cd2Sjpk } 110945916cd2Sjpk if ((error = mk_unalloc(optflag, dm)) != 0) { 111045916cd2Sjpk if (!(optflag & FORCE)) 111145916cd2Sjpk goto out; 111245916cd2Sjpk } 111345916cd2Sjpk if (system_labeled == 0) { 1114*10ddde3aSaj if ((error = _newdac(fname, DA_UID, DA_GID, 111545916cd2Sjpk DEALLOC_MODE)) != 0) { 1116*10ddde3aSaj (void) _newdac(file_name, DA_UID, DA_GID, 111745916cd2Sjpk ALLOC_ERR_MODE); 111845916cd2Sjpk goto out; 111945916cd2Sjpk } 112045916cd2Sjpk } 112145916cd2Sjpk /* 112245916cd2Sjpk * if we are deallocating device owned by someone else, 112345916cd2Sjpk * pass the owner's uid to the cleaning script. 112445916cd2Sjpk */ 112545916cd2Sjpk nuid = (stat_buf.st_uid == uid) ? uid : stat_buf.st_uid; 112645916cd2Sjpk error = exec_clean(optflag, da->da_devname, da->da_devexec, nuid, 112745916cd2Sjpk devzone, DEALLOC_CLEAN); 112845916cd2Sjpk if (error != 0) { 112945916cd2Sjpk if (!(optflag & (FORCE | FORCE_ALL))) { 113045916cd2Sjpk error = CLEANERR; 113145916cd2Sjpk (void) mk_error(dm); 113245916cd2Sjpk } else { 113345916cd2Sjpk error = 0; 113445916cd2Sjpk } 113545916cd2Sjpk } 113645916cd2Sjpk 113745916cd2Sjpk out: 113845916cd2Sjpk if (dm_new) 113945916cd2Sjpk freedmapent(dm_new); 114045916cd2Sjpk return (error); 114145916cd2Sjpk } 114245916cd2Sjpk 114345916cd2Sjpk int 1144*10ddde3aSaj _allocate_dev(int optflag, uid_t uid, devalloc_t *da, char *zonename, 1145*10ddde3aSaj int *lock_fd) 114645916cd2Sjpk { 114745916cd2Sjpk int i; 114845916cd2Sjpk int bytes = 0; 114945916cd2Sjpk int error = 0; 115045916cd2Sjpk int is_authorized = 0; 115145916cd2Sjpk int dealloc_optflag = 0; 115245916cd2Sjpk char *fname = NULL; 115345916cd2Sjpk char file_name[MAXPATHLEN]; 115445916cd2Sjpk devmap_t *dm; 115545916cd2Sjpk struct stat stat_buf; 115645916cd2Sjpk struct state_file sf; 115745916cd2Sjpk struct zone_path zpath; 115845916cd2Sjpk 115945916cd2Sjpk zpath.count = 0; 116045916cd2Sjpk zpath.path = NULL; 116145916cd2Sjpk setdmapent(); 116245916cd2Sjpk if ((dm = getdmapnam(da->da_devname)) == NULL) { 116345916cd2Sjpk enddmapent(); 116445916cd2Sjpk dprintf("Unable to find %s in device map database\n", 116545916cd2Sjpk da->da_devname); 116645916cd2Sjpk return (NODMAPERR); 116745916cd2Sjpk } 116845916cd2Sjpk enddmapent(); 116945916cd2Sjpk if (system_labeled) { 117045916cd2Sjpk if (_dev_file_name(&sf, dm) != 0) { 117145916cd2Sjpk freedmapent(dm); 117245916cd2Sjpk dprintf("Unable to find %s device files\n", 117345916cd2Sjpk da->da_devname); 117445916cd2Sjpk error = NODMAPERR; 117545916cd2Sjpk goto out; 117645916cd2Sjpk } 117745916cd2Sjpk fname = sf.sf_path; 117845916cd2Sjpk } else { 117945916cd2Sjpk bytes = snprintf(file_name, MAXPATHLEN, "%s/%s", DAC_DIR, 118045916cd2Sjpk da->da_devname); 118145916cd2Sjpk if (bytes <= 0) { 118245916cd2Sjpk error = DEVNAMEERR; 118345916cd2Sjpk goto out; 118445916cd2Sjpk } else if (bytes >= MAXPATHLEN) { 118545916cd2Sjpk dprintf("device name %s is too long.\n", 118645916cd2Sjpk da->da_devname); 118745916cd2Sjpk error = DEVLONGERR; 118845916cd2Sjpk goto out; 118945916cd2Sjpk } 119045916cd2Sjpk fname = file_name; 119145916cd2Sjpk } 119245916cd2Sjpk 119345916cd2Sjpk (void) audit_allocate_device(fname); 119445916cd2Sjpk 119545916cd2Sjpk if (stat(fname, &stat_buf) != 0) { 119645916cd2Sjpk dprintf("Unable to stat %s\n", fname); 11977c478bd9Sstevel@tonic-gate dperror("Error:"); 119845916cd2Sjpk error = DACACCERR; 119945916cd2Sjpk goto out; 12007c478bd9Sstevel@tonic-gate } 120145916cd2Sjpk if (DEV_ERRORED(stat_buf)) { 120245916cd2Sjpk error = DEVSTATEERR; 120345916cd2Sjpk goto out; 120445916cd2Sjpk } 120545916cd2Sjpk is_authorized = _is_dev_authorized(da, uid); 120645916cd2Sjpk if (is_authorized == ALLOC_BY_NONE) { 120745916cd2Sjpk dprintf("Device %s is not allocatable\n", da->da_devname); 120845916cd2Sjpk error = UAUTHERR; 120945916cd2Sjpk goto out; 121045916cd2Sjpk } else if (!is_authorized && !(optflag & USERNAME)) { 121145916cd2Sjpk dprintf("User %d is unauthorized to allocate\n", (int)uid); 121245916cd2Sjpk error = UAUTHERR; 121345916cd2Sjpk goto out; 121445916cd2Sjpk } 121545916cd2Sjpk if (system_labeled) { 121645916cd2Sjpk /* 121745916cd2Sjpk * check if label of the zone to which the device is being 121845916cd2Sjpk * allocated is within the device label range. 121945916cd2Sjpk */ 122045916cd2Sjpk if (_check_label(da, zonename, uid, CHECK_DRANGE) != 0) { 122145916cd2Sjpk error = LABELRNGERR; 122245916cd2Sjpk goto out; 122345916cd2Sjpk } 122445916cd2Sjpk } 122545916cd2Sjpk if (check_devs(dm) == -1) { 122645916cd2Sjpk error = DSPMISSERR; 122745916cd2Sjpk goto out; 122845916cd2Sjpk } 12297c478bd9Sstevel@tonic-gate if (DEV_ALLOCATED(stat_buf)) { 123045916cd2Sjpk if (optflag & FORCE) { 123145916cd2Sjpk if (optflag & SILENT) 123245916cd2Sjpk dealloc_optflag = FORCE|SILENT; 123340e2b7c9Spaulson else 123445916cd2Sjpk dealloc_optflag = FORCE; 123545916cd2Sjpk if (_deallocate_dev(dealloc_optflag, da, dm, uid, 1236*10ddde3aSaj zonename, lock_fd)) { 12377c478bd9Sstevel@tonic-gate dprintf("Couldn't force deallocate device %s\n", 123845916cd2Sjpk da->da_devname); 123945916cd2Sjpk error = CNTFRCERR; 124045916cd2Sjpk goto out; 12417c478bd9Sstevel@tonic-gate } 12427c478bd9Sstevel@tonic-gate } else if (stat_buf.st_uid == uid) { 124345916cd2Sjpk error = PREALLOCERR; 124445916cd2Sjpk goto out; 12457c478bd9Sstevel@tonic-gate } else { 124645916cd2Sjpk error = ALLOCUERR; 124745916cd2Sjpk goto out; 124845916cd2Sjpk } 124945916cd2Sjpk } 125045916cd2Sjpk /* All checks passed, time to lock and allocate */ 1251*10ddde3aSaj if ((*lock_fd = lock_dev(fname, &stat_buf)) == -1) { 1252*10ddde3aSaj error = DEVLKERR; 125345916cd2Sjpk goto out; 1254*10ddde3aSaj } 125545916cd2Sjpk if (system_labeled) { 125645916cd2Sjpk /* 125745916cd2Sjpk * Run the cleaning program; it also mounts allocated 125845916cd2Sjpk * device if required. 125945916cd2Sjpk */ 126045916cd2Sjpk error = exec_clean(optflag, da->da_devname, da->da_devexec, uid, 126145916cd2Sjpk zonename, ALLOC_CLEAN); 1262*10ddde3aSaj if (error != DEVCLEAN_OK) { 1263*10ddde3aSaj switch (error) { 1264*10ddde3aSaj case DEVCLEAN_ERROR: 1265*10ddde3aSaj case DEVCLEAN_SYSERR: 1266*10ddde3aSaj dprintf("allocate: " 1267*10ddde3aSaj "Error in device clean program %s\n", 1268*10ddde3aSaj da->da_devexec); 126945916cd2Sjpk error = CLEANERR; 127045916cd2Sjpk (void) mk_error(dm); 127145916cd2Sjpk goto out; 1272*10ddde3aSaj case DEVCLEAN_BADMOUNT: 1273*10ddde3aSaj dprintf("allocate: Failed to mount device %s\n", 1274*10ddde3aSaj da->da_devexec); 1275*10ddde3aSaj goto out; 1276*10ddde3aSaj case DEVCLEAN_MOUNTOK: 1277*10ddde3aSaj break; 1278*10ddde3aSaj default: 1279*10ddde3aSaj error = 0; 1280*10ddde3aSaj goto out; 1281*10ddde3aSaj } 128245916cd2Sjpk } 128345916cd2Sjpk /* 128445916cd2Sjpk * If not mounted, create zonelinks, if this is not the 128545916cd2Sjpk * global zone. 128645916cd2Sjpk */ 128745916cd2Sjpk if ((strcmp(zonename, GLOBAL_ZONENAME) != 0) && 1288*10ddde3aSaj (error != DEVCLEAN_MOUNTOK)) { 128945916cd2Sjpk if (create_znode(zonename, &zpath, dm) != 0) { 129045916cd2Sjpk error = ZONEERR; 129145916cd2Sjpk goto out; 129245916cd2Sjpk } 129345916cd2Sjpk } 129445916cd2Sjpk } 129545916cd2Sjpk 129645916cd2Sjpk (void) audit_allocate_list(dm->dmap_devlist); 129745916cd2Sjpk 129845916cd2Sjpk if ((error = mk_alloc(dm, uid, &zpath)) != 0) { 129945916cd2Sjpk (void) mk_unalloc(optflag, dm); 130045916cd2Sjpk goto out; 130145916cd2Sjpk } 130245916cd2Sjpk 130345916cd2Sjpk if (system_labeled == 0) { 130445916cd2Sjpk if ((error = _newdac(file_name, uid, getgid(), 130545916cd2Sjpk ALLOC_MODE)) != 0) { 1306*10ddde3aSaj (void) _newdac(file_name, DA_UID, DA_GID, 130745916cd2Sjpk ALLOC_ERR_MODE); 130845916cd2Sjpk goto out; 130945916cd2Sjpk } 131045916cd2Sjpk } 131145916cd2Sjpk error = 0; 131245916cd2Sjpk out: 131345916cd2Sjpk if (zpath.count) { 131445916cd2Sjpk for (i = 0; i < zpath.count; i++) 131545916cd2Sjpk free(zpath.path[i]); 131645916cd2Sjpk free(zpath.path); 131745916cd2Sjpk } 131845916cd2Sjpk freedmapent(dm); 131945916cd2Sjpk return (error); 132045916cd2Sjpk } 132145916cd2Sjpk 132245916cd2Sjpk void 1323facf4a8dSllai1 _store_devnames(int *count, struct dev_names *dnms, char *zonename, 132445916cd2Sjpk devalloc_t *da, int flag) 132545916cd2Sjpk { 132645916cd2Sjpk int i; 132745916cd2Sjpk 132845916cd2Sjpk dnms->dnames = (char **)realloc(dnms->dnames, 132945916cd2Sjpk (*count + 1) * sizeof (char *)); 133045916cd2Sjpk if (da) { 133145916cd2Sjpk dnms->dnames[*count] = strdup(da->da_devname); 133245916cd2Sjpk (*count)++; 133345916cd2Sjpk } else { 133445916cd2Sjpk dnms->dnames[*count] = NULL; 133545916cd2Sjpk if (flag == DA_ADD_ZONE) 133645916cd2Sjpk (void) update_device(dnms->dnames, zonename, 133745916cd2Sjpk DA_ADD_ZONE); 133845916cd2Sjpk else if (flag == DA_REMOVE_ZONE) 133945916cd2Sjpk (void) update_device(dnms->dnames, NULL, 134045916cd2Sjpk DA_REMOVE_ZONE); 134145916cd2Sjpk for (i = 0; i < *count; i++) 134245916cd2Sjpk free(dnms->dnames[i]); 134345916cd2Sjpk free(dnms->dnames); 134445916cd2Sjpk } 134545916cd2Sjpk } 134645916cd2Sjpk 134745916cd2Sjpk int 134845916cd2Sjpk allocate(int optflag, uid_t uid, char *device, char *zonename) 134945916cd2Sjpk { 135045916cd2Sjpk int count = 0; 135145916cd2Sjpk int error = 0; 1352*10ddde3aSaj int lock_fd = -1; 135345916cd2Sjpk devalloc_t *da; 1354facf4a8dSllai1 struct dev_names dnms; 135545916cd2Sjpk 135645916cd2Sjpk if (optflag & (FORCE | USERID | USERNAME)) { 135745916cd2Sjpk if (!_is_authorized(DEVICE_REVOKE_AUTH, getuid())) 135845916cd2Sjpk return (UAUTHERR); 135945916cd2Sjpk } 136045916cd2Sjpk dnms.dnames = NULL; 136145916cd2Sjpk setdaent(); 136245916cd2Sjpk if (optflag & TYPE) { 136345916cd2Sjpk /* 136445916cd2Sjpk * allocate devices of this type 136545916cd2Sjpk */ 136645916cd2Sjpk while ((da = getdatype(device)) != NULL) { 136745916cd2Sjpk if (system_labeled && 136845916cd2Sjpk da_check_logindevperm(da->da_devname)) { 136945916cd2Sjpk freedaent(da); 13707c478bd9Sstevel@tonic-gate continue; 13717c478bd9Sstevel@tonic-gate } 137245916cd2Sjpk dprintf("trying to allocate %s\n", da->da_devname); 1373*10ddde3aSaj error = _allocate_dev(optflag, uid, da, zonename, 1374*10ddde3aSaj &lock_fd); 137545916cd2Sjpk if (system_labeled && (error == 0)) { 137645916cd2Sjpk /* 137745916cd2Sjpk * we need to record in device_allocate the 137845916cd2Sjpk * label (zone name) at which this device is 137945916cd2Sjpk * being allocated. store this device entry. 138045916cd2Sjpk */ 138145916cd2Sjpk _store_devnames(&count, &dnms, zonename, da, 0); 13827c478bd9Sstevel@tonic-gate } 138345916cd2Sjpk freedaent(da); 138445916cd2Sjpk error = 0; 13857c478bd9Sstevel@tonic-gate } 138645916cd2Sjpk } else { 138745916cd2Sjpk /* 138845916cd2Sjpk * allocate this device 138945916cd2Sjpk */ 139045916cd2Sjpk if ((da = getdanam(device)) == NULL) { 13917c478bd9Sstevel@tonic-gate enddaent(); 139245916cd2Sjpk return (NODAERR); 139345916cd2Sjpk } 139445916cd2Sjpk if (system_labeled && da_check_logindevperm(device)) { 139545916cd2Sjpk freedaent(da); 139645916cd2Sjpk return (LOGINDEVPERMERR); 139745916cd2Sjpk } 139845916cd2Sjpk dprintf("trying to allocate %s\n", da->da_devname); 1399*10ddde3aSaj error = _allocate_dev(optflag, uid, da, zonename, &lock_fd); 140045916cd2Sjpk /* 140145916cd2Sjpk * we need to record in device_allocate the label (zone name) 140245916cd2Sjpk * at which this device is being allocated. store this device 140345916cd2Sjpk * entry. 140445916cd2Sjpk */ 140545916cd2Sjpk if (system_labeled && (error == 0)) 140645916cd2Sjpk _store_devnames(&count, &dnms, zonename, da, 0); 140745916cd2Sjpk freedaent(da); 1408*10ddde3aSaj if (error == DEVCLEAN_BADMOUNT) 1409*10ddde3aSaj error = 0; 141045916cd2Sjpk } 141145916cd2Sjpk enddaent(); 1412*10ddde3aSaj if (lock_fd != -1) 1413*10ddde3aSaj (void) close(lock_fd); 141445916cd2Sjpk /* 141545916cd2Sjpk * add to device_allocate labels (zone names) for the devices we 141645916cd2Sjpk * allocated. 141745916cd2Sjpk */ 141845916cd2Sjpk if (dnms.dnames) 141945916cd2Sjpk _store_devnames(&count, &dnms, zonename, NULL, DA_ADD_ZONE); 142045916cd2Sjpk 14217c478bd9Sstevel@tonic-gate return (error); 14227c478bd9Sstevel@tonic-gate } 142345916cd2Sjpk 142445916cd2Sjpk /* ARGSUSED */ 142545916cd2Sjpk int 142645916cd2Sjpk deallocate(int optflag, uid_t uid, char *device, char *zonename) 142745916cd2Sjpk { 142845916cd2Sjpk int count = 0; 142945916cd2Sjpk int error = 0; 1430*10ddde3aSaj int lock_fd = -1; 1431*10ddde3aSaj char *class = NULL; 143245916cd2Sjpk devalloc_t *da; 1433facf4a8dSllai1 struct dev_names dnms; 143445916cd2Sjpk 143545916cd2Sjpk if (optflag & (FORCE | FORCE_ALL)) { 143645916cd2Sjpk if (!_is_authorized(DEVICE_REVOKE_AUTH, getuid())) 143745916cd2Sjpk return (UAUTHERR); 143845916cd2Sjpk } 143945916cd2Sjpk if (optflag & FORCE_ALL) 144045916cd2Sjpk optflag |= FORCE; 144145916cd2Sjpk dnms.dnames = NULL; 144245916cd2Sjpk setdaent(); 144345916cd2Sjpk if (optflag & FORCE_ALL) { 144445916cd2Sjpk /* 144545916cd2Sjpk * deallocate all devices 144645916cd2Sjpk */ 144745916cd2Sjpk while ((da = getdaent()) != NULL) { 144845916cd2Sjpk if (system_labeled && 144945916cd2Sjpk da_check_logindevperm(da->da_devname)) { 145045916cd2Sjpk freedaent(da); 145145916cd2Sjpk continue; 145245916cd2Sjpk } 145345916cd2Sjpk dprintf("trying to deallocate %s\n", da->da_devname); 145445916cd2Sjpk error = _deallocate_dev(optflag, da, NULL, uid, 1455*10ddde3aSaj zonename, &lock_fd); 145645916cd2Sjpk if (system_labeled && (error == 0)) { 145745916cd2Sjpk /* 145845916cd2Sjpk * we need to remove this device's allocation 145945916cd2Sjpk * label (zone name) from device_allocate. 146045916cd2Sjpk * store this device name. 146145916cd2Sjpk */ 146245916cd2Sjpk _store_devnames(&count, &dnms, zonename, da, 0); 146345916cd2Sjpk } 146445916cd2Sjpk freedaent(da); 146545916cd2Sjpk error = 0; 146645916cd2Sjpk } 1467*10ddde3aSaj } else if (system_labeled && (optflag & TYPE)) { 146845916cd2Sjpk /* 146945916cd2Sjpk * deallocate all devices of this type 147045916cd2Sjpk */ 147145916cd2Sjpk while ((da = getdatype(device)) != NULL) { 147245916cd2Sjpk if (da_check_logindevperm(da->da_devname)) { 147345916cd2Sjpk freedaent(da); 147445916cd2Sjpk continue; 147545916cd2Sjpk } 147645916cd2Sjpk dprintf("trying to deallocate %s\n", da->da_devname); 147745916cd2Sjpk error = _deallocate_dev(optflag, da, NULL, uid, 1478*10ddde3aSaj zonename, &lock_fd); 147945916cd2Sjpk if (error == 0) { 148045916cd2Sjpk /* 148145916cd2Sjpk * we need to remove this device's allocation 148245916cd2Sjpk * label (zone name) from device_allocate. 148345916cd2Sjpk * store this device name. 148445916cd2Sjpk */ 148545916cd2Sjpk _store_devnames(&count, &dnms, zonename, da, 0); 148645916cd2Sjpk } 148745916cd2Sjpk freedaent(da); 148845916cd2Sjpk error = 0; 148945916cd2Sjpk } 1490*10ddde3aSaj } else if (system_labeled && (optflag & CLASS)) { 1491*10ddde3aSaj /* 1492*10ddde3aSaj * deallocate all devices of this class (for sunray) 1493*10ddde3aSaj */ 1494*10ddde3aSaj while ((da = getdaent()) != NULL) { 1495*10ddde3aSaj class = kva_match(da->da_devopts, DAOPT_CLASS); 1496*10ddde3aSaj if (class && (strcmp(class, device) == 0)) { 1497*10ddde3aSaj dprintf("trying to deallocate %s\n", 1498*10ddde3aSaj da->da_devname); 1499*10ddde3aSaj error = _deallocate_dev(optflag, da, NULL, uid, 1500*10ddde3aSaj zonename, &lock_fd); 1501*10ddde3aSaj if (error == 0) { 1502*10ddde3aSaj /* 1503*10ddde3aSaj * we need to remove this device's 1504*10ddde3aSaj * allocation label (zone name) from 1505*10ddde3aSaj * device_allocate. store this device 1506*10ddde3aSaj * name. 1507*10ddde3aSaj */ 1508*10ddde3aSaj _store_devnames(&count, &dnms, zonename, 1509*10ddde3aSaj da, 0); 1510*10ddde3aSaj } 1511*10ddde3aSaj error = 0; 1512*10ddde3aSaj } 1513*10ddde3aSaj freedaent(da); 1514*10ddde3aSaj } 151545916cd2Sjpk } else if (!(optflag & TYPE)) { 151645916cd2Sjpk /* 151745916cd2Sjpk * deallocate this device 151845916cd2Sjpk */ 151945916cd2Sjpk if ((da = getdanam(device)) == NULL) { 152045916cd2Sjpk enddaent(); 152145916cd2Sjpk return (NODAERR); 152245916cd2Sjpk } 152345916cd2Sjpk if (system_labeled && da_check_logindevperm(da->da_devname)) { 152445916cd2Sjpk freedaent(da); 152545916cd2Sjpk return (LOGINDEVPERMERR); 152645916cd2Sjpk } 152745916cd2Sjpk dprintf("trying to deallocate %s\n", da->da_devname); 1528*10ddde3aSaj error = _deallocate_dev(optflag, da, NULL, uid, zonename, 1529*10ddde3aSaj &lock_fd); 153045916cd2Sjpk if (system_labeled && (error == 0)) { 153145916cd2Sjpk /* 153245916cd2Sjpk * we need to remove this device's allocation label 153345916cd2Sjpk * (zone name) from device_allocate. store this 153445916cd2Sjpk * device name. 153545916cd2Sjpk */ 153645916cd2Sjpk _store_devnames(&count, &dnms, zonename, da, 0); 153745916cd2Sjpk } 153845916cd2Sjpk freedaent(da); 1539*10ddde3aSaj if (error == DEVCLEAN_BADMOUNT) 1540*10ddde3aSaj error = 0; 154145916cd2Sjpk } 154245916cd2Sjpk enddaent(); 1543*10ddde3aSaj if (lock_fd != -1) 1544*10ddde3aSaj (void) close(lock_fd); 154545916cd2Sjpk /* 154645916cd2Sjpk * remove from device_allocate labels (zone names) for the devices we 154745916cd2Sjpk * deallocated. 154845916cd2Sjpk */ 154945916cd2Sjpk if (dnms.dnames) 155045916cd2Sjpk _store_devnames(&count, &dnms, zonename, NULL, DA_REMOVE_ZONE); 155145916cd2Sjpk 155245916cd2Sjpk return (error); 155345916cd2Sjpk } 155445916cd2Sjpk 155545916cd2Sjpk static int 155645916cd2Sjpk _dev_file_name(struct state_file *sfp, devmap_t *dm) 155745916cd2Sjpk { 155845916cd2Sjpk sfp->sf_flags = 0; 155945916cd2Sjpk /* if devlist is generated, never leave device in error state */ 156045916cd2Sjpk if (dm->dmap_devlist[0] == '`') 156145916cd2Sjpk sfp->sf_flags |= SFF_NO_ERROR; 156245916cd2Sjpk if (dm->dmap_devarray == NULL || 156345916cd2Sjpk dm->dmap_devarray[0] == NULL) 156445916cd2Sjpk return (NODMAPERR); 156545916cd2Sjpk (void) strncpy(sfp->sf_path, dm->dmap_devarray[0], 156645916cd2Sjpk sizeof (sfp->sf_path)); 156745916cd2Sjpk sfp->sf_path[sizeof (sfp->sf_path) - 1] = '\0'; 156845916cd2Sjpk if (sfp->sf_path[0] == '\0') { 156945916cd2Sjpk dprintf("dev_file_name: no device list for %s\n", 157045916cd2Sjpk dm->dmap_devname); 157145916cd2Sjpk return (NODMAPERR); 157245916cd2Sjpk } 157345916cd2Sjpk 157445916cd2Sjpk return (0); 157545916cd2Sjpk } 157645916cd2Sjpk 157745916cd2Sjpk /* 157845916cd2Sjpk * _check_label - 157945916cd2Sjpk * checks the device label range against zone label, which is also 158045916cd2Sjpk * user's current label. 158145916cd2Sjpk * returns 0 if in range, -1 for all other conditions. 158245916cd2Sjpk * 158345916cd2Sjpk */ 158445916cd2Sjpk 158545916cd2Sjpk static int 158645916cd2Sjpk _check_label(devalloc_t *da, char *zonename, uid_t uid, int flag) 158745916cd2Sjpk { 158845916cd2Sjpk int err; 158945916cd2Sjpk int in_range = 0; 159045916cd2Sjpk char *alloczone, *lstr; 159145916cd2Sjpk char pw_buf[NSS_BUFLEN_PASSWD]; 159245916cd2Sjpk blrange_t *range; 159345916cd2Sjpk m_label_t *zlabel; 159445916cd2Sjpk struct passwd pw_ent; 159545916cd2Sjpk 159645916cd2Sjpk if ((da == NULL) || (zonename == NULL)) 159745916cd2Sjpk return (-1); 159845916cd2Sjpk 159945916cd2Sjpk if ((zlabel = getzonelabelbyname(zonename)) == NULL) { 160045916cd2Sjpk dprintf("unable to get label for %s zone\n", zonename); 160145916cd2Sjpk return (-1); 160245916cd2Sjpk } 160345916cd2Sjpk if (flag == CHECK_DRANGE) { 160445916cd2Sjpk blrange_t drange; 160545916cd2Sjpk 160645916cd2Sjpk drange.lower_bound = blabel_alloc(); 160745916cd2Sjpk lstr = kva_match(da->da_devopts, DAOPT_MINLABEL); 160845916cd2Sjpk if (lstr == NULL) { 160945916cd2Sjpk bsllow(drange.lower_bound); 161045916cd2Sjpk } else if (stobsl(lstr, drange.lower_bound, NO_CORRECTION, 161145916cd2Sjpk &err) == 0) { 161245916cd2Sjpk dprintf("bad min_label for device %s\n", 161345916cd2Sjpk da->da_devname); 161445916cd2Sjpk free(zlabel); 161545916cd2Sjpk blabel_free(drange.lower_bound); 161645916cd2Sjpk return (-1); 161745916cd2Sjpk } 161845916cd2Sjpk drange.upper_bound = blabel_alloc(); 161945916cd2Sjpk lstr = kva_match(da->da_devopts, DAOPT_MAXLABEL); 162045916cd2Sjpk if (lstr == NULL) { 162145916cd2Sjpk bslhigh(drange.upper_bound); 162245916cd2Sjpk } else if (stobsl(lstr, drange.upper_bound, NO_CORRECTION, 162345916cd2Sjpk &err) == 0) { 162445916cd2Sjpk dprintf("bad max_label for device %s\n", 162545916cd2Sjpk da->da_devname); 162645916cd2Sjpk free(zlabel); 162745916cd2Sjpk blabel_free(drange.lower_bound); 162845916cd2Sjpk blabel_free(drange.upper_bound); 162945916cd2Sjpk return (-1); 163045916cd2Sjpk } 163145916cd2Sjpk if (blinrange(zlabel, &drange) == 0) { 163245916cd2Sjpk char *zlbl = NULL, *min = NULL, *max = NULL; 163345916cd2Sjpk 163445916cd2Sjpk (void) bsltos(zlabel, &zlbl, 0, 0); 163545916cd2Sjpk (void) bsltos(drange.lower_bound, &min, 0, 0); 163645916cd2Sjpk (void) bsltos(drange.upper_bound, &max, 0, 0); 163745916cd2Sjpk dprintf("%s zone label ", zonename); 163845916cd2Sjpk dprintf("%s outside device label range: ", zlbl); 163945916cd2Sjpk dprintf("min - %s, ", min); 164045916cd2Sjpk dprintf("max - %s\n", max); 164145916cd2Sjpk free(zlabel); 164245916cd2Sjpk blabel_free(drange.lower_bound); 164345916cd2Sjpk blabel_free(drange.upper_bound); 164445916cd2Sjpk return (-1); 164545916cd2Sjpk } 164645916cd2Sjpk } else if (flag == CHECK_URANGE) { 164745916cd2Sjpk if (getpwuid_r(uid, &pw_ent, pw_buf, sizeof (pw_buf)) == NULL) { 164845916cd2Sjpk dprintf("Unable to get passwd entry for userid %d\n", 164945916cd2Sjpk (int)uid); 165045916cd2Sjpk free(zlabel); 165145916cd2Sjpk return (-1); 165245916cd2Sjpk } 165345916cd2Sjpk if ((range = getuserrange(pw_ent.pw_name)) == NULL) { 165445916cd2Sjpk dprintf("Unable to get label range for userid %d\n", 165545916cd2Sjpk (int)uid); 165645916cd2Sjpk free(zlabel); 165745916cd2Sjpk return (-1); 165845916cd2Sjpk } 165945916cd2Sjpk in_range = blinrange(zlabel, range); 166045916cd2Sjpk free(zlabel); 166145916cd2Sjpk blabel_free(range->lower_bound); 166245916cd2Sjpk blabel_free(range->upper_bound); 166345916cd2Sjpk free(range); 166445916cd2Sjpk if (in_range == 0) { 166545916cd2Sjpk dprintf("%s device label ", da->da_devname); 166645916cd2Sjpk dprintf("out of user %d label range\n", (int)uid); 166745916cd2Sjpk return (-1); 166845916cd2Sjpk } 166945916cd2Sjpk } else if (flag == CHECK_ZLABEL) { 167045916cd2Sjpk alloczone = kva_match(da->da_devopts, DAOPT_ZONE); 167145916cd2Sjpk if (alloczone == NULL) { 167245916cd2Sjpk free(zlabel); 167345916cd2Sjpk return (-1); 167445916cd2Sjpk } 167545916cd2Sjpk if (strcmp(zonename, alloczone) != 0) { 167645916cd2Sjpk dprintf("%s zone is different than ", zonename); 167745916cd2Sjpk dprintf("%s zone to which the device ", alloczone); 167845916cd2Sjpk dprintf("%s is allocated\n", da->da_devname); 167945916cd2Sjpk free(zlabel); 168045916cd2Sjpk return (-1); 168145916cd2Sjpk } 168245916cd2Sjpk } 168345916cd2Sjpk free(zlabel); 168445916cd2Sjpk 168545916cd2Sjpk return (0); 168645916cd2Sjpk } 168745916cd2Sjpk 168845916cd2Sjpk int 168945916cd2Sjpk create_znode(char *zonename, struct zone_path *zpath, devmap_t *list) 169045916cd2Sjpk { 169145916cd2Sjpk int size; 169245916cd2Sjpk int len = 0; 169345916cd2Sjpk int fcount = 0; 169445916cd2Sjpk char *p, *tmpfile, *zoneroot; 169545916cd2Sjpk char **file; 169645916cd2Sjpk char zonepath[MAXPATHLEN]; 1697facf4a8dSllai1 di_prof_t prof = NULL; 169845916cd2Sjpk 169945916cd2Sjpk file = list->dmap_devarray; 170045916cd2Sjpk if (file == NULL) 170145916cd2Sjpk return (NODMAPERR); 170245916cd2Sjpk if ((zoneroot = getzonerootbyname(zonename)) == NULL) { 170345916cd2Sjpk dprintf("unable to get label for %s zone\n", zonename); 170445916cd2Sjpk return (1); 170545916cd2Sjpk } 170645916cd2Sjpk (void) strcpy(zonepath, zoneroot); 170745916cd2Sjpk free(zoneroot); 170845916cd2Sjpk len = strlen(zonepath); 170945916cd2Sjpk size = sizeof (zonepath); 1710facf4a8dSllai1 (void) strlcat(zonepath, "/dev", size); 1711facf4a8dSllai1 if (di_prof_init(zonepath, &prof)) { 1712facf4a8dSllai1 dprintf("failed to initialize dev profile at %s\n", zonepath); 171345916cd2Sjpk return (1); 171445916cd2Sjpk } 1715facf4a8dSllai1 zonepath[len] = '\0'; 1716facf4a8dSllai1 for (; *file != NULL; file++) { 171745916cd2Sjpk /* 171845916cd2Sjpk * First time initialization 171945916cd2Sjpk */ 172045916cd2Sjpk tmpfile = strdup(*file); 172145916cd2Sjpk 172245916cd2Sjpk /* 172345916cd2Sjpk * Most devices have pathnames starting in /dev 172445916cd2Sjpk * but SunRay devices do not. In SRRS 3.1 they use /tmp. 172545916cd2Sjpk * 172645916cd2Sjpk * If the device pathname is not in /dev then create 172745916cd2Sjpk * a symbolic link to it and put the device in /dev 172845916cd2Sjpk */ 172945916cd2Sjpk if (strncmp(tmpfile, "/dev/", strlen("/dev/")) != 0) { 173045916cd2Sjpk char *linkdir; 173145916cd2Sjpk char srclinkdir[MAXPATHLEN]; 173245916cd2Sjpk char dstlinkdir[MAXPATHLEN]; 173345916cd2Sjpk 173445916cd2Sjpk linkdir = strchr(tmpfile + 1, '/'); 173545916cd2Sjpk p = strchr(linkdir + 1, '/'); 173645916cd2Sjpk *p = '\0'; 173745916cd2Sjpk (void) strcpy(dstlinkdir, "/dev"); 173845916cd2Sjpk (void) strncat(dstlinkdir, linkdir, MAXPATHLEN); 173945916cd2Sjpk (void) snprintf(srclinkdir, MAXPATHLEN, "%s/root%s", 174045916cd2Sjpk zonepath, tmpfile); 174145916cd2Sjpk (void) symlink(dstlinkdir, srclinkdir); 174245916cd2Sjpk *p = '/'; 174345916cd2Sjpk (void) strncat(dstlinkdir, p, MAXPATHLEN); 174445916cd2Sjpk free(tmpfile); 174545916cd2Sjpk tmpfile = strdup(dstlinkdir); 174645916cd2Sjpk } 1747facf4a8dSllai1 if (di_prof_add_dev(prof, tmpfile)) { 1748facf4a8dSllai1 dprintf("failed to add %s to profile\n", tmpfile); 1749facf4a8dSllai1 di_prof_fini(prof); 175045916cd2Sjpk return (1); 175145916cd2Sjpk } 175245916cd2Sjpk if (strlcat(zonepath, tmpfile, size) >= size) { 175345916cd2Sjpk dprintf("Buffer overflow in create_znode for %s\n", 175445916cd2Sjpk *file); 175545916cd2Sjpk free(tmpfile); 1756facf4a8dSllai1 di_prof_fini(prof); 175745916cd2Sjpk return (1); 175845916cd2Sjpk } 175945916cd2Sjpk free(tmpfile); 176045916cd2Sjpk fcount++; 176145916cd2Sjpk if ((zpath->path = (char **)realloc(zpath->path, 1762facf4a8dSllai1 (fcount * sizeof (char *)))) == NULL) { 1763facf4a8dSllai1 di_prof_fini(prof); 176445916cd2Sjpk return (1); 1765facf4a8dSllai1 } 176645916cd2Sjpk zpath->path[zpath->count] = strdup(zonepath); 176745916cd2Sjpk zpath->count = fcount; 176845916cd2Sjpk zonepath[len] = '\0'; 176945916cd2Sjpk } 177045916cd2Sjpk 1771facf4a8dSllai1 if (di_prof_commit(prof)) 1772facf4a8dSllai1 dprintf("failed to add devices to zone %s\n", zonename); 1773facf4a8dSllai1 di_prof_fini(prof); 1774facf4a8dSllai1 177545916cd2Sjpk return (0); 177645916cd2Sjpk } 177745916cd2Sjpk 177845916cd2Sjpk int 177945916cd2Sjpk remove_znode(char *zonename, devmap_t *dm) 178045916cd2Sjpk { 178145916cd2Sjpk int len = 0; 178245916cd2Sjpk char *zoneroot; 178345916cd2Sjpk char **file; 178445916cd2Sjpk char zonepath[MAXPATHLEN]; 1785facf4a8dSllai1 di_prof_t prof = NULL; 178645916cd2Sjpk 178745916cd2Sjpk file = dm->dmap_devarray; 178845916cd2Sjpk if (file == NULL) 178945916cd2Sjpk return (NODMAPERR); 179045916cd2Sjpk if ((zoneroot = getzonerootbyname(zonename)) == NULL) { 179145916cd2Sjpk (void) snprintf(zonepath, MAXPATHLEN, "/zone/%s", zonename); 179245916cd2Sjpk } else { 179345916cd2Sjpk (void) strcpy(zonepath, zoneroot); 179445916cd2Sjpk free(zoneroot); 179545916cd2Sjpk } 179645916cd2Sjpk /* 179745916cd2Sjpk * To support SunRay we will just deal with the 179845916cd2Sjpk * file in /dev, not the symlinks. 179945916cd2Sjpk */ 180045916cd2Sjpk (void) strncat(zonepath, "/dev", MAXPATHLEN); 180145916cd2Sjpk len = strlen(zonepath); 1802facf4a8dSllai1 if (di_prof_init(zonepath, &prof)) { 1803facf4a8dSllai1 dprintf("failed to initialize dev profile at %s\n", zonepath); 1804facf4a8dSllai1 return (1); 1805facf4a8dSllai1 } 180645916cd2Sjpk for (; *file != NULL; file++) { 180745916cd2Sjpk char *devrelpath; 180845916cd2Sjpk 180945916cd2Sjpk /* 181045916cd2Sjpk * remove device node from zone. 181145916cd2Sjpk * 181245916cd2Sjpk * SunRay devices don't start with /dev 181345916cd2Sjpk * so skip over first directory to make 181445916cd2Sjpk * sure it is /dev. SunRay devices in zones 181545916cd2Sjpk * will have a symlink into /dev but 181645916cd2Sjpk * we don't ever delete it. 181745916cd2Sjpk */ 181845916cd2Sjpk devrelpath = strchr(*file + 1, '/'); 181945916cd2Sjpk 1820facf4a8dSllai1 if (di_prof_add_exclude(prof, devrelpath + 1)) { 1821facf4a8dSllai1 dprintf("Failed exclude %s in dev profile\n", *file); 1822facf4a8dSllai1 di_prof_fini(prof); 182345916cd2Sjpk return (1); 182445916cd2Sjpk } 182545916cd2Sjpk zonepath[len] = '\0'; 182645916cd2Sjpk } 182745916cd2Sjpk 1828facf4a8dSllai1 if (di_prof_commit(prof)) 1829facf4a8dSllai1 dprintf("failed to remove devices from zone %s\n", zonename); 1830facf4a8dSllai1 di_prof_fini(prof); 183145916cd2Sjpk return (0); 183245916cd2Sjpk } 183345916cd2Sjpk 183445916cd2Sjpk int 183545916cd2Sjpk update_device(char **devnames, char *zonename, int flag) 183645916cd2Sjpk { 183745916cd2Sjpk int len, rc; 183845916cd2Sjpk char *optstr = NULL; 183945916cd2Sjpk da_args dargs; 184045916cd2Sjpk devinfo_t devinfo; 184145916cd2Sjpk 184245916cd2Sjpk dargs.optflag = flag; 184345916cd2Sjpk dargs.optflag |= DA_UPDATE|DA_ALLOC_ONLY; 184445916cd2Sjpk dargs.rootdir = NULL; 184545916cd2Sjpk dargs.devnames = devnames; 184645916cd2Sjpk devinfo.devname = devinfo.devtype = devinfo.devauths = devinfo.devexec = 184745916cd2Sjpk devinfo.devlist = NULL; 184845916cd2Sjpk if (dargs.optflag & DA_ADD_ZONE) { 184945916cd2Sjpk len = strlen(DAOPT_ZONE) + strlen(zonename) + 3; 185045916cd2Sjpk if ((optstr = (char *)malloc(len)) == NULL) 185145916cd2Sjpk return (-1); 185245916cd2Sjpk (void) snprintf(optstr, len, "%s%s%s", DAOPT_ZONE, KV_ASSIGN, 185345916cd2Sjpk zonename); 185445916cd2Sjpk devinfo.devopts = optstr; 185545916cd2Sjpk } 185645916cd2Sjpk dargs.devinfo = &devinfo; 185745916cd2Sjpk 185845916cd2Sjpk rc = da_update_device(&dargs); 185945916cd2Sjpk 186045916cd2Sjpk if (optstr) 186145916cd2Sjpk free(optstr); 186245916cd2Sjpk 186345916cd2Sjpk return (rc); 186445916cd2Sjpk } 1865