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 /* 2340e2b7c9Spaulson * Copyright 2006 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> 65*facf4a8dSllai1 #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) 7945916cd2Sjpk #define DEV_INVALID(sbuf) (((sbuf).st_mode & ~S_IFMT) == ALLOC_INVALID) 807c478bd9Sstevel@tonic-gate #define DEV_ALLOCATED(sbuf) ((sbuf).st_uid != ALLOC_UID || \ 8145916cd2Sjpk !(((sbuf).st_mode & ~S_IFMT) == DEALLOC_MODE || \ 8245916cd2Sjpk DEV_ERRORED(sbuf) || DEV_INVALID(sbuf))) 837c478bd9Sstevel@tonic-gate 8445916cd2Sjpk #define ALLOC_CLEAN "-A" 8545916cd2Sjpk #define DEALLOC_CLEAN "-D" 8645916cd2Sjpk #define DAC_DIR "/etc/security/dev" 877c478bd9Sstevel@tonic-gate #define DEVICE_AUTH_SEPARATOR "," 8845916cd2Sjpk #define LOCALDEVICE "/dev/console" 897c478bd9Sstevel@tonic-gate #define PROCFS "/proc/" 9045916cd2Sjpk #define SFF_NO_ERROR 0x1 9145916cd2Sjpk 9245916cd2Sjpk #define ALLOC_BY_NONE -1 9345916cd2Sjpk #define CHECK_DRANGE 1 9445916cd2Sjpk #define CHECK_URANGE 2 9545916cd2Sjpk #define CHECK_ZLABEL 3 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate extern void audit_allocate_list(char *); 987c478bd9Sstevel@tonic-gate extern void audit_allocate_device(char *); 997c478bd9Sstevel@tonic-gate 10045916cd2Sjpk extern int system_labeled; 1017c478bd9Sstevel@tonic-gate extern char *newenv[]; 1027c478bd9Sstevel@tonic-gate 10345916cd2Sjpk struct state_file { 10445916cd2Sjpk int sf_flags; 10545916cd2Sjpk char sf_path[MAXPATHLEN]; 10645916cd2Sjpk }; 10745916cd2Sjpk 10845916cd2Sjpk struct file_info { 10945916cd2Sjpk struct stat fi_stat; 11045916cd2Sjpk char *fi_message; 11145916cd2Sjpk }; 11245916cd2Sjpk 11345916cd2Sjpk struct zone_path { 11445916cd2Sjpk int count; 11545916cd2Sjpk char **path; 11645916cd2Sjpk }; 11745916cd2Sjpk 118*facf4a8dSllai1 struct dev_names { 11945916cd2Sjpk char **dnames; 12045916cd2Sjpk }; 12145916cd2Sjpk 12245916cd2Sjpk static int _dev_file_name(struct state_file *, devmap_t *); 12345916cd2Sjpk static int lock_dev(char *); 12445916cd2Sjpk static int _check_label(devalloc_t *, char *, uid_t, int); 12545916cd2Sjpk static int create_znode(char *, struct zone_path *, devmap_t *); 12645916cd2Sjpk static int remove_znode(char *, devmap_t *); 12745916cd2Sjpk static int update_device(char **, char *, int); 12845916cd2Sjpk 1297c478bd9Sstevel@tonic-gate /* 13045916cd2Sjpk * checks if the invoking user is local to the device 1317c478bd9Sstevel@tonic-gate */ 13245916cd2Sjpk /*ARGSUSED*/ 13345916cd2Sjpk int 13445916cd2Sjpk _is_local(uid_t uid) 1357c478bd9Sstevel@tonic-gate { 13645916cd2Sjpk struct stat statbuf; 1377c478bd9Sstevel@tonic-gate 13845916cd2Sjpk if (stat(LOCALDEVICE, &statbuf) == 0 && 13945916cd2Sjpk statbuf.st_uid == uid) 1407c478bd9Sstevel@tonic-gate return (1); 14145916cd2Sjpk 1427c478bd9Sstevel@tonic-gate return (0); 1437c478bd9Sstevel@tonic-gate } 1447c478bd9Sstevel@tonic-gate 14545916cd2Sjpk /* 14645916cd2Sjpk * Checks if the user with the specified uid has the specified authorization 14745916cd2Sjpk */ 14845916cd2Sjpk int 14945916cd2Sjpk _is_authorized(char *auths, uid_t uid) 1507c478bd9Sstevel@tonic-gate { 15145916cd2Sjpk char *dcp, *authlist, *lasts; 15245916cd2Sjpk char pw_buf[NSS_BUFLEN_PASSWD]; 15345916cd2Sjpk struct passwd pw_ent; 1547c478bd9Sstevel@tonic-gate 15545916cd2Sjpk /* 15645916cd2Sjpk * first, the easy cases 15745916cd2Sjpk */ 15845916cd2Sjpk if (strcmp(auths, "@") == 0) 15945916cd2Sjpk return (1); 16045916cd2Sjpk if (strcmp(auths, "*") == 0) 16145916cd2Sjpk return (ALLOC_BY_NONE); 16245916cd2Sjpk if (getpwuid_r(uid, &pw_ent, pw_buf, sizeof (pw_buf)) == NULL) 16345916cd2Sjpk return (0); 16445916cd2Sjpk if (strpbrk(auths, DEVICE_AUTH_SEPARATOR) == NULL) 16545916cd2Sjpk return (chkauthattr(auths, pw_ent.pw_name)); 16645916cd2Sjpk authlist = strdup(auths); 16745916cd2Sjpk if (authlist == NULL) 16845916cd2Sjpk return (0); 16945916cd2Sjpk for (dcp = authlist; 17045916cd2Sjpk (dcp = strtok_r(dcp, DEVICE_AUTH_SEPARATOR, &lasts)) != NULL; 17145916cd2Sjpk dcp = NULL) { 17245916cd2Sjpk if (chkauthattr(dcp, pw_ent.pw_name)) 17345916cd2Sjpk break; 17445916cd2Sjpk } 17545916cd2Sjpk free(authlist); 1767c478bd9Sstevel@tonic-gate 17745916cd2Sjpk return (dcp != NULL); 1787c478bd9Sstevel@tonic-gate } 17945916cd2Sjpk 18045916cd2Sjpk /* 18145916cd2Sjpk * Checks if the specified user has authorization for the device 18245916cd2Sjpk */ 18345916cd2Sjpk int 18445916cd2Sjpk _is_dev_authorized(devalloc_t *da, uid_t uid) 18545916cd2Sjpk { 18645916cd2Sjpk int ares; 18745916cd2Sjpk char *auth_list, *dcp, *subauth = NULL; 18845916cd2Sjpk 18945916cd2Sjpk auth_list = da->da_devauth; 19045916cd2Sjpk if (auth_list == NULL) 19145916cd2Sjpk return (0); 19245916cd2Sjpk dcp = strpbrk(auth_list, KV_TOKEN_DELIMIT); 19345916cd2Sjpk if (dcp == NULL) 19445916cd2Sjpk return (_is_authorized(auth_list, uid)); 19545916cd2Sjpk if (_is_local(uid)) { 19645916cd2Sjpk /* the local authorization is before the separator */ 19745916cd2Sjpk ares = dcp - auth_list; 19845916cd2Sjpk subauth = malloc(ares + 1); 19945916cd2Sjpk if (subauth == NULL) 20045916cd2Sjpk return (0); 20145916cd2Sjpk (void) strlcpy(subauth, auth_list, (ares + 1)); 20245916cd2Sjpk auth_list = subauth; 20345916cd2Sjpk } else 20445916cd2Sjpk auth_list = dcp + 1; 20545916cd2Sjpk ares = _is_authorized(auth_list, uid); 20645916cd2Sjpk if (subauth != NULL) 20745916cd2Sjpk free(subauth); 20845916cd2Sjpk 20945916cd2Sjpk return (ares); 2107c478bd9Sstevel@tonic-gate } 21145916cd2Sjpk 21245916cd2Sjpk int 21345916cd2Sjpk check_devs(devmap_t *dm) 21445916cd2Sjpk { 21545916cd2Sjpk int status = 0; 21645916cd2Sjpk char **file; 21745916cd2Sjpk 21845916cd2Sjpk if (dm->dmap_devarray == NULL) 21945916cd2Sjpk return (NODMAPERR); 22045916cd2Sjpk for (file = dm->dmap_devarray; *file != NULL; file++) { 22145916cd2Sjpk if ((status = access(*file, F_OK)) == -1) { 22245916cd2Sjpk dprintf("Unable to access file %s\n", *file); 22345916cd2Sjpk break; 22445916cd2Sjpk } 22545916cd2Sjpk } 22645916cd2Sjpk 22745916cd2Sjpk return (status); 22845916cd2Sjpk } 22945916cd2Sjpk 23045916cd2Sjpk int 23145916cd2Sjpk print_da_defs(da_defs_t *da_defs) 23245916cd2Sjpk { 23345916cd2Sjpk char optbuf[BUFSIZ]; 23445916cd2Sjpk char *p = NULL; 23545916cd2Sjpk 23645916cd2Sjpk if (da_defs->devopts == NULL) { 23745916cd2Sjpk dprintf("No default attributes for %s\n", da_defs->devtype); 23845916cd2Sjpk return (DEFATTRSERR); 23945916cd2Sjpk } 24045916cd2Sjpk (void) printf("dev_type=%s\n", da_defs->devtype); 24145916cd2Sjpk if (_kva2str(da_defs->devopts, optbuf, sizeof (optbuf), KV_ASSIGN, 24245916cd2Sjpk KV_TOKEN_DELIMIT) == 0) { 24345916cd2Sjpk if (p = rindex(optbuf, ':')) 24445916cd2Sjpk *p = '\0'; 24545916cd2Sjpk (void) printf("\t%s\n", optbuf); 24645916cd2Sjpk } 24745916cd2Sjpk 2487c478bd9Sstevel@tonic-gate return (0); 2497c478bd9Sstevel@tonic-gate } 2507c478bd9Sstevel@tonic-gate 25145916cd2Sjpk void 25245916cd2Sjpk print_dev_attrs(int optflag, devalloc_t *da, devmap_t *dm, 25345916cd2Sjpk struct file_info *fip) 2547c478bd9Sstevel@tonic-gate { 25545916cd2Sjpk char *p = NULL; 25645916cd2Sjpk char optbuf[BUFSIZ]; 2577c478bd9Sstevel@tonic-gate 25845916cd2Sjpk (void) printf("device=%s%s", dm->dmap_devname, KV_DELIMITER); 25945916cd2Sjpk (void) printf("type=%s%s", dm->dmap_devtype, KV_DELIMITER); 26045916cd2Sjpk (void) printf("auths=%s%s", 26145916cd2Sjpk (da->da_devauth ? da->da_devauth : ""), KV_DELIMITER); 26245916cd2Sjpk (void) printf("clean=%s%s", 26345916cd2Sjpk (da->da_devexec ? da->da_devexec : ""), KV_DELIMITER); 26445916cd2Sjpk if (da->da_devopts != NULL) { 26545916cd2Sjpk if (_kva2str(da->da_devopts, optbuf, sizeof (optbuf), 26645916cd2Sjpk KV_ASSIGN, KV_TOKEN_DELIMIT) == 0) { 26745916cd2Sjpk if (p = rindex(optbuf, ':')) 26845916cd2Sjpk *p = '\0'; 26945916cd2Sjpk (void) printf("%s", optbuf); 27045916cd2Sjpk } 27145916cd2Sjpk } 27245916cd2Sjpk (void) printf("%s", KV_DELIMITER); 27345916cd2Sjpk if (optflag & WINDOWING) { 27445916cd2Sjpk if (DEV_INVALID(fip->fi_stat)) 27545916cd2Sjpk (void) printf("owner=/INVALID:%s%s", fip->fi_message, 27645916cd2Sjpk KV_DELIMITER); 27745916cd2Sjpk else if (DEV_ERRORED(fip->fi_stat)) 27845916cd2Sjpk (void) printf("owner=/ERROR%s", KV_DELIMITER); 27945916cd2Sjpk else if (!DEV_ALLOCATED(fip->fi_stat)) 28045916cd2Sjpk (void) printf("owner=/FREE%s", KV_DELIMITER); 28145916cd2Sjpk else 28245916cd2Sjpk (void) printf("owner=%ld%s", fip->fi_stat.st_uid, 28345916cd2Sjpk KV_DELIMITER); 28445916cd2Sjpk } 28545916cd2Sjpk (void) printf("files=%s", dm->dmap_devlist); 28645916cd2Sjpk (void) printf("\n"); 28745916cd2Sjpk } 28845916cd2Sjpk 28945916cd2Sjpk void 29045916cd2Sjpk print_dev(devmap_t *dm) 29145916cd2Sjpk { 29245916cd2Sjpk char **file; 29345916cd2Sjpk 29445916cd2Sjpk (void) printf(gettext("device: %s "), dm->dmap_devname); 29545916cd2Sjpk (void) printf(gettext("type: %s "), dm->dmap_devtype); 2967c478bd9Sstevel@tonic-gate (void) printf(gettext("files:")); 29745916cd2Sjpk file = dm->dmap_devarray; 29845916cd2Sjpk if (file != NULL) { 29945916cd2Sjpk for (; *file != NULL; file++) 30045916cd2Sjpk (void) printf(" %s", *file); 3017c478bd9Sstevel@tonic-gate } 3027c478bd9Sstevel@tonic-gate (void) printf("\n"); 3037c478bd9Sstevel@tonic-gate } 3047c478bd9Sstevel@tonic-gate 30545916cd2Sjpk /* ARGSUSED */ 30645916cd2Sjpk int 30745916cd2Sjpk _list_device(int optflag, uid_t uid, devalloc_t *da, char *zonename) 3087c478bd9Sstevel@tonic-gate { 30945916cd2Sjpk int bytes = 0; 31045916cd2Sjpk int error = 0; 31145916cd2Sjpk int is_authorized = 0; 31245916cd2Sjpk char *fname = NULL; 3137c478bd9Sstevel@tonic-gate char file_name[MAXPATHLEN]; 31445916cd2Sjpk devmap_t *dm; 31545916cd2Sjpk struct file_info fi; 31645916cd2Sjpk struct state_file sf; 3177c478bd9Sstevel@tonic-gate 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(); 32645916cd2Sjpk if (system_labeled) { 32745916cd2Sjpk if ((error = _dev_file_name(&sf, dm)) != 0) { 32845916cd2Sjpk freedmapent(dm); 32945916cd2Sjpk dprintf("Unable to find %s device files\n", 33045916cd2Sjpk da->da_devname); 33145916cd2Sjpk error = NODMAPERR; 33245916cd2Sjpk goto out; 3337c478bd9Sstevel@tonic-gate } 33445916cd2Sjpk fname = sf.sf_path; 33545916cd2Sjpk } else { 33645916cd2Sjpk bytes = snprintf(file_name, MAXPATHLEN, "%s/%s", DAC_DIR, 33745916cd2Sjpk da->da_devname); 33845916cd2Sjpk if (bytes <= 0) { 33945916cd2Sjpk error = DEVNAMEERR; 34045916cd2Sjpk goto out; 34145916cd2Sjpk } else if (bytes >= MAXPATHLEN) { 34245916cd2Sjpk dprintf("device name %s is too long.\n", 34345916cd2Sjpk da->da_devname); 34445916cd2Sjpk error = DEVLONGERR; 34545916cd2Sjpk goto out; 3467c478bd9Sstevel@tonic-gate } 34745916cd2Sjpk fname = file_name; 34845916cd2Sjpk } 34945916cd2Sjpk if (stat(fname, &fi.fi_stat) != 0) { 35045916cd2Sjpk dprintf("Unable to stat %s\n", fname); 3517c478bd9Sstevel@tonic-gate dperror("Error:"); 35245916cd2Sjpk error = DACACCERR; 35345916cd2Sjpk goto out; 35445916cd2Sjpk } 35545916cd2Sjpk if (optflag & USERID) 35645916cd2Sjpk is_authorized = 1; 35745916cd2Sjpk else 35845916cd2Sjpk is_authorized = _is_dev_authorized(da, uid); 35945916cd2Sjpk if (optflag & LISTFREE) { /* list_devices -n */ 36045916cd2Sjpk /* 36145916cd2Sjpk * list all free devices 36245916cd2Sjpk */ 36345916cd2Sjpk if (DEV_ALLOCATED(fi.fi_stat)) { 36445916cd2Sjpk error = PREALLOCERR; 36545916cd2Sjpk goto out; 36645916cd2Sjpk } 36745916cd2Sjpk if (system_labeled) { 36845916cd2Sjpk /* 36945916cd2Sjpk * for this free device, check if - 37045916cd2Sjpk * 1. user has authorization to allocate 37145916cd2Sjpk * 2. the zone label is within the label range of the 37245916cd2Sjpk * device 37345916cd2Sjpk */ 37445916cd2Sjpk if (is_authorized == ALLOC_BY_NONE) { 37545916cd2Sjpk error = DAUTHERR; 37645916cd2Sjpk goto out; 37745916cd2Sjpk } else if (is_authorized == 0) { 37845916cd2Sjpk error = UAUTHERR; 37945916cd2Sjpk goto out; 38045916cd2Sjpk } 38145916cd2Sjpk if (_check_label(da, zonename, uid, 38245916cd2Sjpk CHECK_DRANGE) != 0) { 38345916cd2Sjpk error = LABELRNGERR; 38445916cd2Sjpk goto out; 38545916cd2Sjpk } 38645916cd2Sjpk } 38745916cd2Sjpk } else if (optflag & LISTALLOC) { /* list_devices -u */ 38845916cd2Sjpk /* 38945916cd2Sjpk * list all allocated devices 39045916cd2Sjpk */ 39145916cd2Sjpk if (!DEV_ALLOCATED(fi.fi_stat)) { 39245916cd2Sjpk error = DEVNALLOCERR; 39345916cd2Sjpk goto out; 39445916cd2Sjpk } 39545916cd2Sjpk if (fi.fi_stat.st_uid != uid) { 39645916cd2Sjpk error = DEVSTATEERR; 39745916cd2Sjpk goto out; 39845916cd2Sjpk } 39945916cd2Sjpk if (system_labeled) { 40045916cd2Sjpk /* 40145916cd2Sjpk * check if the zone label equals the label at which 40245916cd2Sjpk * the device is allocated. 40345916cd2Sjpk */ 40445916cd2Sjpk if (_check_label(da, zonename, uid, 40545916cd2Sjpk CHECK_ZLABEL) != 0) { 40645916cd2Sjpk error = LABELRNGERR; 40745916cd2Sjpk goto out; 40845916cd2Sjpk } 40945916cd2Sjpk } 41045916cd2Sjpk } else if (optflag & LISTALL) { /* list_devices -l */ 41145916cd2Sjpk /* 41245916cd2Sjpk * list all devices - free and allocated - available 41345916cd2Sjpk */ 41445916cd2Sjpk if (DEV_ALLOCATED(fi.fi_stat)) { 41545916cd2Sjpk if (optflag & WINDOWING && 41645916cd2Sjpk (is_authorized == ALLOC_BY_NONE)) { 41745916cd2Sjpk /* 41845916cd2Sjpk * don't complain if we're here for the GUI. 41945916cd2Sjpk */ 42045916cd2Sjpk error = 0; 42145916cd2Sjpk } else if (fi.fi_stat.st_uid != uid) { 42245916cd2Sjpk if (!(optflag & WINDOWING)) { 42345916cd2Sjpk error = ALLOCUERR; 42445916cd2Sjpk goto out; 42545916cd2Sjpk } 42645916cd2Sjpk } 42745916cd2Sjpk if (system_labeled && !(optflag & WINDOWING)) { 42845916cd2Sjpk /* 42945916cd2Sjpk * if we're not displaying in the GUI, 43045916cd2Sjpk * check if the zone label equals the label 43145916cd2Sjpk * at which the device is allocated. 43245916cd2Sjpk */ 43345916cd2Sjpk if (_check_label(da, zonename, uid, 43445916cd2Sjpk CHECK_ZLABEL) != 0) { 43545916cd2Sjpk error = LABELRNGERR; 43645916cd2Sjpk goto out; 43745916cd2Sjpk } 43845916cd2Sjpk } 43945916cd2Sjpk } else if (system_labeled && !(optflag & WINDOWING)) { 44045916cd2Sjpk /* 44145916cd2Sjpk * if we're not displaying in the GUI, 44245916cd2Sjpk * for this free device, check if - 44345916cd2Sjpk * 1. user has authorization to allocate 44445916cd2Sjpk * 2. the zone label is within the label range of the 44545916cd2Sjpk * device 44645916cd2Sjpk */ 44745916cd2Sjpk if (is_authorized == ALLOC_BY_NONE) { 44845916cd2Sjpk error = DAUTHERR; 44945916cd2Sjpk goto out; 45045916cd2Sjpk } else if (is_authorized == 0) { 45145916cd2Sjpk error = UAUTHERR; 45245916cd2Sjpk goto out; 45345916cd2Sjpk } 45445916cd2Sjpk if (_check_label(da, zonename, uid, 45545916cd2Sjpk CHECK_DRANGE) != 0) { 45645916cd2Sjpk error = LABELRNGERR; 45745916cd2Sjpk goto out; 45845916cd2Sjpk } 45945916cd2Sjpk } 46045916cd2Sjpk } 46145916cd2Sjpk if (system_labeled && DEV_ERRORED(fi.fi_stat) && !(optflag & LISTALL)) { 46245916cd2Sjpk error = DEVSTATEERR; 46345916cd2Sjpk goto out; 46445916cd2Sjpk } 46545916cd2Sjpk if (check_devs(dm) == -1) { 46645916cd2Sjpk error = DSPMISSERR; 46745916cd2Sjpk goto out; 46845916cd2Sjpk } 46945916cd2Sjpk if (optflag & LISTATTRS) 47045916cd2Sjpk print_dev_attrs(optflag, da, dm, &fi); 47145916cd2Sjpk else 47245916cd2Sjpk print_dev(dm); 47345916cd2Sjpk 47445916cd2Sjpk error = 0; 47545916cd2Sjpk 47645916cd2Sjpk out: 47745916cd2Sjpk freedmapent(dm); 47845916cd2Sjpk return (error); 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate 48145916cd2Sjpk /* ARGSUSED */ 48245916cd2Sjpk int 48345916cd2Sjpk list_devices(int optflag, uid_t uid, char *device, char *zonename) 48445916cd2Sjpk { 48545916cd2Sjpk int error = 0; 48645916cd2Sjpk da_defs_t *da_defs; 48745916cd2Sjpk devalloc_t *da; 4887c478bd9Sstevel@tonic-gate 48945916cd2Sjpk if (system_labeled && optflag & WINDOWING && !(optflag & LISTATTRS)) { 49045916cd2Sjpk /* 49145916cd2Sjpk * Private interface for GUI. 49245916cd2Sjpk */ 49345916cd2Sjpk (void) lock_dev(NULL); 49445916cd2Sjpk (void) puts(DA_DB_LOCK); 4957c478bd9Sstevel@tonic-gate return (0); 4967c478bd9Sstevel@tonic-gate } 49745916cd2Sjpk if (optflag & USERID) { 49845916cd2Sjpk /* 49945916cd2Sjpk * we need device.revoke to list someone else's devices 50045916cd2Sjpk */ 50145916cd2Sjpk if (!_is_authorized(DEVICE_REVOKE_AUTH, getuid())) 50245916cd2Sjpk return (UAUTHERR); 50345916cd2Sjpk } 50445916cd2Sjpk if (system_labeled) { 50545916cd2Sjpk if (!(optflag & USERID) && 50645916cd2Sjpk !_is_authorized(DEFAULT_DEV_ALLOC_AUTH, uid)) 50745916cd2Sjpk /* 50845916cd2Sjpk * we need device.allocate to list our devices 50945916cd2Sjpk */ 51045916cd2Sjpk return (UAUTHERR); 51145916cd2Sjpk if (optflag & LISTDEFS) { 51245916cd2Sjpk /* 51345916cd2Sjpk * list default attrs from devalloc_defaults 51445916cd2Sjpk */ 51545916cd2Sjpk setdadefent(); 51645916cd2Sjpk if (device) { 51745916cd2Sjpk /* 51845916cd2Sjpk * list default attrs for this device type 51945916cd2Sjpk */ 52045916cd2Sjpk da_defs = getdadeftype(device); 52145916cd2Sjpk if (da_defs == NULL) { 52245916cd2Sjpk enddadefent(); 52345916cd2Sjpk dprintf("No default attributes for " 52445916cd2Sjpk "%s\n", device); 52545916cd2Sjpk return (DEFATTRSERR); 52645916cd2Sjpk } 52745916cd2Sjpk error = print_da_defs(da_defs); 52845916cd2Sjpk freedadefent(da_defs); 52945916cd2Sjpk } else { 53045916cd2Sjpk /* 53145916cd2Sjpk * list everything in devalloc_defaults 53245916cd2Sjpk */ 53345916cd2Sjpk while ((da_defs = getdadefent()) != NULL) { 53445916cd2Sjpk (void) print_da_defs(da_defs); 53545916cd2Sjpk freedadefent(da_defs); 53645916cd2Sjpk } 53745916cd2Sjpk } 53845916cd2Sjpk enddadefent(); 53945916cd2Sjpk return (error); 54045916cd2Sjpk } 5417c478bd9Sstevel@tonic-gate } 5427c478bd9Sstevel@tonic-gate setdaent(); 5437c478bd9Sstevel@tonic-gate if (device) { 54445916cd2Sjpk /* 54545916cd2Sjpk * list this device 54645916cd2Sjpk */ 54745916cd2Sjpk if ((da = getdanam(device)) == NULL) { 5487c478bd9Sstevel@tonic-gate enddaent(); 54945916cd2Sjpk return (NODAERR); 55045916cd2Sjpk } 55145916cd2Sjpk error = _list_device(optflag, uid, da, zonename); 55245916cd2Sjpk freedaent(da); 55345916cd2Sjpk } else { 55445916cd2Sjpk /* 55545916cd2Sjpk * list all devices 55645916cd2Sjpk */ 55745916cd2Sjpk while ((da = getdaent()) != NULL) { 55845916cd2Sjpk (void) _list_device(optflag, uid, da, zonename); 55945916cd2Sjpk freedaent(da); 56045916cd2Sjpk } 56145916cd2Sjpk } 56245916cd2Sjpk enddaent(); 56345916cd2Sjpk 56445916cd2Sjpk return (error); 5657c478bd9Sstevel@tonic-gate } 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate /* 5687c478bd9Sstevel@tonic-gate * Set the DAC characteristics of the file. 5697c478bd9Sstevel@tonic-gate * This uses a fancy chmod() by setting a minimal ACL which sets the mode 5707c478bd9Sstevel@tonic-gate * and discards any existing ACL. 5717c478bd9Sstevel@tonic-gate */ 57245916cd2Sjpk int 57345916cd2Sjpk _newdac(char *file, uid_t owner, gid_t group, o_mode_t mode) 5747c478bd9Sstevel@tonic-gate { 5757c478bd9Sstevel@tonic-gate int err = 0; 5767c478bd9Sstevel@tonic-gate 57745916cd2Sjpk if (mode == ALLOC_MODE) { 5787c478bd9Sstevel@tonic-gate if (chown(file, owner, group) == -1) { 57945916cd2Sjpk dperror("newdac: unable to chown"); 58045916cd2Sjpk err = CHOWNERR; 58145916cd2Sjpk } 58245916cd2Sjpk } else do { 58345916cd2Sjpk if (chown(file, owner, group) == -1) { 58445916cd2Sjpk dperror("newdac: unable to chown"); 58545916cd2Sjpk err = CHOWNERR; 5867c478bd9Sstevel@tonic-gate } 5877c478bd9Sstevel@tonic-gate } while (fdetach(file) == 0); 5887c478bd9Sstevel@tonic-gate 58945916cd2Sjpk if (err) 59045916cd2Sjpk return (err); 59145916cd2Sjpk 59245916cd2Sjpk if (strncmp(file, "/dev/", strlen("/dev/")) != 0) { 59345916cd2Sjpk /* 59445916cd2Sjpk * This could be a SunRay device that is in /tmp. 59545916cd2Sjpk */ 59645916cd2Sjpk if (chmod(file, mode) == -1) { 59745916cd2Sjpk dperror("newdac: unable to chmod"); 59845916cd2Sjpk err = SETACLERR; 59945916cd2Sjpk } 60045916cd2Sjpk } else { 601fa9e4066Sahrens err = acl_strip(file, owner, group, (mode_t)mode); 60245916cd2Sjpk } 603fa9e4066Sahrens 604fa9e4066Sahrens if (err != 0) { 60545916cd2Sjpk dperror("newdac: unable to setacl"); 60645916cd2Sjpk err = SETACLERR; 6077c478bd9Sstevel@tonic-gate } 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate return (err); 6107c478bd9Sstevel@tonic-gate } 6117c478bd9Sstevel@tonic-gate 6127c478bd9Sstevel@tonic-gate static int 6137c478bd9Sstevel@tonic-gate lock_dev(char *file) 6147c478bd9Sstevel@tonic-gate { 61545916cd2Sjpk int lockfd = -1; 6167c478bd9Sstevel@tonic-gate 61745916cd2Sjpk if ((file == NULL) || system_labeled) 61845916cd2Sjpk file = DA_DEV_LOCK; 6197c478bd9Sstevel@tonic-gate dprintf("locking %s\n", file); 62045916cd2Sjpk if ((lockfd = open(file, O_RDWR | O_CREAT, 0600)) == -1) { 62145916cd2Sjpk dperror("lock_dev: cannot open lock file"); 62245916cd2Sjpk return (DEVLKERR); 6237c478bd9Sstevel@tonic-gate } 62445916cd2Sjpk if (lockf(lockfd, F_TLOCK, 0) == -1) { 62545916cd2Sjpk dperror("lock_dev: cannot set lock"); 62645916cd2Sjpk return (DEVLKERR); 6277c478bd9Sstevel@tonic-gate } 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate return (0); 6307c478bd9Sstevel@tonic-gate } 6317c478bd9Sstevel@tonic-gate 63245916cd2Sjpk int 63345916cd2Sjpk mk_alloc(devmap_t *list, uid_t uid, struct zone_path *zpath) 6347c478bd9Sstevel@tonic-gate { 63545916cd2Sjpk int i; 63645916cd2Sjpk int error = 0; 63745916cd2Sjpk char **file; 63845916cd2Sjpk gid_t gid = getgid(); 63945916cd2Sjpk mode_t mode = ALLOC_MODE; 6407c478bd9Sstevel@tonic-gate 64145916cd2Sjpk file = list->dmap_devarray; 64245916cd2Sjpk if (file == NULL) 64345916cd2Sjpk return (NODMAPERR); 64445916cd2Sjpk for (; *file != NULL; file++) { 64545916cd2Sjpk dprintf("Allocating %s\n", *file); 64645916cd2Sjpk if ((error = _newdac(*file, uid, gid, mode)) != 0) { 64745916cd2Sjpk (void) _newdac(*file, ALLOC_ERRID, ALLOC_GID, 6487c478bd9Sstevel@tonic-gate ALLOC_ERR_MODE); 64945916cd2Sjpk break; 65045916cd2Sjpk } 65145916cd2Sjpk } 65245916cd2Sjpk if (system_labeled && zpath->count && (error == 0)) { 65345916cd2Sjpk /* 65445916cd2Sjpk * mark as allocated any new device nodes that we 65545916cd2Sjpk * created in local zone 65645916cd2Sjpk */ 65745916cd2Sjpk for (i = 0; i < zpath->count; i++) { 65845916cd2Sjpk dprintf("Allocating %s\n", zpath->path[i]); 65945916cd2Sjpk if ((error = _newdac(zpath->path[i], uid, gid, 66045916cd2Sjpk mode)) != 0) { 66145916cd2Sjpk (void) _newdac(zpath->path[i], ALLOC_ERRID, 66245916cd2Sjpk ALLOC_GID, ALLOC_ERR_MODE); 66345916cd2Sjpk break; 66445916cd2Sjpk } 66545916cd2Sjpk } 6667c478bd9Sstevel@tonic-gate } 6677c478bd9Sstevel@tonic-gate 66845916cd2Sjpk return (error); 6697c478bd9Sstevel@tonic-gate } 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate /* 6727c478bd9Sstevel@tonic-gate * mk_revoke() is used instead of system("/usr/sbin/fuser -k file") 6737c478bd9Sstevel@tonic-gate * because "/usr/sbin/fuser -k file" kills all processes 6747c478bd9Sstevel@tonic-gate * working with the file, even "vold" (bug #4095152). 6757c478bd9Sstevel@tonic-gate */ 67645916cd2Sjpk int 67745916cd2Sjpk mk_revoke(int optflag, char *file) 6787c478bd9Sstevel@tonic-gate { 6797c478bd9Sstevel@tonic-gate int r = 0, p[2], fp, lock; 68045916cd2Sjpk int fuserpid; 68145916cd2Sjpk char buf[MAXPATHLEN]; 6827c478bd9Sstevel@tonic-gate FILE *ptr; 68345916cd2Sjpk pid_t c_pid; 6847c478bd9Sstevel@tonic-gate prpsinfo_t info; 6857c478bd9Sstevel@tonic-gate 6867c478bd9Sstevel@tonic-gate (void) strcpy(buf, PROCFS); 6877c478bd9Sstevel@tonic-gate /* 68845916cd2Sjpk * vfork() and execl() just to make the same output 6897c478bd9Sstevel@tonic-gate * as before fixing of bug #4095152. 6907c478bd9Sstevel@tonic-gate * The problem is that the "fuser" command prints 6917c478bd9Sstevel@tonic-gate * one part of output into stderr and another into stdout, 6927c478bd9Sstevel@tonic-gate * but user sees them mixed. Of course, better to change "fuser" 6937c478bd9Sstevel@tonic-gate * or to intercept and not to print its output. 6947c478bd9Sstevel@tonic-gate */ 69545916cd2Sjpk if (!(optflag & SILENT)) { 6967c478bd9Sstevel@tonic-gate c_pid = vfork(); 6977c478bd9Sstevel@tonic-gate if (c_pid == -1) 6987c478bd9Sstevel@tonic-gate return (-1); 6997c478bd9Sstevel@tonic-gate if (c_pid == 0) { 7007c478bd9Sstevel@tonic-gate dprintf("first exec fuser %s\n", file); 70145916cd2Sjpk (void) execl("/usr/sbin/fuser", "fuser", file, NULL); 7027c478bd9Sstevel@tonic-gate dperror("first exec fuser"); 7037c478bd9Sstevel@tonic-gate _exit(1); 7047c478bd9Sstevel@tonic-gate } 7057c478bd9Sstevel@tonic-gate 7067c478bd9Sstevel@tonic-gate (void) waitpid(c_pid, &lock, 0); 7077c478bd9Sstevel@tonic-gate dprintf("exit status %x\n", lock); 7087c478bd9Sstevel@tonic-gate if (WEXITSTATUS(lock) != 0) 7097c478bd9Sstevel@tonic-gate return (-1); 7107c478bd9Sstevel@tonic-gate } 71145916cd2Sjpk dprintf("first continuing c_pid=%d\n", (int)c_pid); 7127c478bd9Sstevel@tonic-gate if (pipe(p)) { 7137c478bd9Sstevel@tonic-gate dperror("pipe"); 7147c478bd9Sstevel@tonic-gate return (-1); 7157c478bd9Sstevel@tonic-gate } 71645916cd2Sjpk /* vfork() and execl() to catch output and to process it */ 7177c478bd9Sstevel@tonic-gate c_pid = vfork(); 7187c478bd9Sstevel@tonic-gate if (c_pid == -1) { 7197c478bd9Sstevel@tonic-gate dperror("second vfork"); 7207c478bd9Sstevel@tonic-gate return (-1); 7217c478bd9Sstevel@tonic-gate } 72245916cd2Sjpk dprintf("second continuing c_pid=%d\n", (int)c_pid); 7237c478bd9Sstevel@tonic-gate if (c_pid == 0) { 7247c478bd9Sstevel@tonic-gate (void) close(p[0]); 7257c478bd9Sstevel@tonic-gate (void) close(1); 7267c478bd9Sstevel@tonic-gate (void) fcntl(p[1], F_DUPFD, 1); 7277c478bd9Sstevel@tonic-gate (void) close(p[1]); 7287c478bd9Sstevel@tonic-gate (void) close(2); 7297c478bd9Sstevel@tonic-gate dprintf("second exec fuser %s\n", file); 73045916cd2Sjpk (void) execl("/usr/sbin/fuser", "fuser", file, NULL); 7317c478bd9Sstevel@tonic-gate dperror("second exec fuser"); 7327c478bd9Sstevel@tonic-gate _exit(1); 7337c478bd9Sstevel@tonic-gate } 7347c478bd9Sstevel@tonic-gate (void) close(p[1]); 7357c478bd9Sstevel@tonic-gate if ((ptr = fdopen(p[0], "r")) != NULL) { 7367c478bd9Sstevel@tonic-gate while (!feof(ptr)) { 73745916cd2Sjpk if (fscanf(ptr, "%d", &fuserpid) > 0) { 73845916cd2Sjpk (void) sprintf(buf + strlen(PROCFS), "%d", 73945916cd2Sjpk fuserpid); 7407c478bd9Sstevel@tonic-gate if ((fp = open(buf, O_RDONLY)) == -1) { 7417c478bd9Sstevel@tonic-gate dperror(buf); 7427c478bd9Sstevel@tonic-gate continue; 7437c478bd9Sstevel@tonic-gate } 74445916cd2Sjpk if (ioctl(fp, PIOCPSINFO, 74545916cd2Sjpk (char *)&info) == -1) { 74645916cd2Sjpk dprintf("%d psinfo failed", fuserpid); 7477c478bd9Sstevel@tonic-gate dperror(""); 7487c478bd9Sstevel@tonic-gate (void) close(fp); 7497c478bd9Sstevel@tonic-gate continue; 7507c478bd9Sstevel@tonic-gate } 7517c478bd9Sstevel@tonic-gate (void) close(fp); 7527c478bd9Sstevel@tonic-gate if (strcmp(info.pr_fname, "vold") == NULL) { 75345916cd2Sjpk dprintf("%d matched vold name\n", 75445916cd2Sjpk fuserpid); 7557c478bd9Sstevel@tonic-gate continue; 7567c478bd9Sstevel@tonic-gate } 7577c478bd9Sstevel@tonic-gate dprintf("killing %s", info.pr_fname); 75845916cd2Sjpk dprintf("(%d)\n", fuserpid); 75945916cd2Sjpk if ((r = 76045916cd2Sjpk kill((pid_t)fuserpid, SIGKILL)) == -1) { 76145916cd2Sjpk dprintf("kill %d", fuserpid); 7627c478bd9Sstevel@tonic-gate dperror(""); 7637c478bd9Sstevel@tonic-gate break; 7647c478bd9Sstevel@tonic-gate } 7657c478bd9Sstevel@tonic-gate } 7667c478bd9Sstevel@tonic-gate } 7677c478bd9Sstevel@tonic-gate } else { 76845916cd2Sjpk dperror("fdopen(p[0], r)"); 7697c478bd9Sstevel@tonic-gate r = -1; 7707c478bd9Sstevel@tonic-gate } 7717c478bd9Sstevel@tonic-gate (void) fclose(ptr); 77245916cd2Sjpk 7737c478bd9Sstevel@tonic-gate return (r); 7747c478bd9Sstevel@tonic-gate } 7757c478bd9Sstevel@tonic-gate 77645916cd2Sjpk int 77745916cd2Sjpk mk_unalloc(int optflag, devmap_t *list) 7787c478bd9Sstevel@tonic-gate { 7797c478bd9Sstevel@tonic-gate int error = 0; 7807c478bd9Sstevel@tonic-gate int status; 78145916cd2Sjpk char **file; 7827c478bd9Sstevel@tonic-gate 78345916cd2Sjpk audit_allocate_list(list->dmap_devlist); 78445916cd2Sjpk file = list->dmap_devarray; 78545916cd2Sjpk if (file == NULL) 78645916cd2Sjpk return (NODMAPERR); 78745916cd2Sjpk for (; *file != NULL; file++) { 78845916cd2Sjpk dprintf("Deallocating %s\n", *file); 78945916cd2Sjpk if (mk_revoke(optflag, *file) < 0) { 79045916cd2Sjpk dprintf("mk_unalloc: unable to revoke %s\n", *file); 79145916cd2Sjpk dperror(""); 79245916cd2Sjpk error = CNTFRCERR; 79345916cd2Sjpk } 79445916cd2Sjpk status = _newdac(*file, ALLOC_UID, ALLOC_GID, DEALLOC_MODE); 79545916cd2Sjpk if (error == 0) 79645916cd2Sjpk error = status; 79745916cd2Sjpk 79845916cd2Sjpk } 79945916cd2Sjpk 80045916cd2Sjpk return (error); 80145916cd2Sjpk } 80245916cd2Sjpk 80345916cd2Sjpk int 80445916cd2Sjpk mk_error(devmap_t *list) 80545916cd2Sjpk { 80645916cd2Sjpk int status = 0; 80745916cd2Sjpk char **file; 80845916cd2Sjpk 80945916cd2Sjpk audit_allocate_list(list->dmap_devlist); 81045916cd2Sjpk file = list->dmap_devarray; 81145916cd2Sjpk if (file == NULL) 81245916cd2Sjpk return (NODMAPERR); 81345916cd2Sjpk for (; *file != NULL; file++) { 81445916cd2Sjpk dprintf("Putting %s in error state\n", *file); 81545916cd2Sjpk status = _newdac(*file, ALLOC_ERRID, ALLOC_GID, ALLOC_ERR_MODE); 81645916cd2Sjpk } 81745916cd2Sjpk 81845916cd2Sjpk return (status); 81945916cd2Sjpk } 82045916cd2Sjpk 82145916cd2Sjpk int 82245916cd2Sjpk exec_clean(int optflag, char *devname, char *path, uid_t uid, char *zonename, 82345916cd2Sjpk char *clean_arg) 82445916cd2Sjpk { 82545916cd2Sjpk int c; 82645916cd2Sjpk int status = 0, exit_status; 82745916cd2Sjpk char *mode, *cmd, *wdwcmd, *zoneroot; 82845916cd2Sjpk char *devzone = zonename; 82945916cd2Sjpk char wdwpath[PATH_MAX]; 83045916cd2Sjpk char zonepath[MAXPATHLEN]; 83145916cd2Sjpk char title[100]; 83245916cd2Sjpk char pw_buf[NSS_BUFLEN_PASSWD]; 83345916cd2Sjpk struct passwd pw_ent; 83445916cd2Sjpk 83545916cd2Sjpk zonepath[0] = '\0'; 83645916cd2Sjpk if (system_labeled) { 83745916cd2Sjpk if ((zoneroot = getzonerootbyname(zonename)) == NULL) { 83845916cd2Sjpk if (strcmp(clean_arg, ALLOC_CLEAN) == 0) { 83945916cd2Sjpk return (-1); 84045916cd2Sjpk } else if (optflag & FORCE) { 84145916cd2Sjpk (void) strcpy(zonepath, "/"); 84245916cd2Sjpk devzone = GLOBAL_ZONENAME; 84345916cd2Sjpk } else { 84445916cd2Sjpk dprintf("unable to get label for %s zone\n", 84545916cd2Sjpk zonename); 84645916cd2Sjpk return (-1); 84745916cd2Sjpk } 84845916cd2Sjpk } else { 84945916cd2Sjpk (void) strcpy(zonepath, zoneroot); 85045916cd2Sjpk free(zoneroot); 85145916cd2Sjpk } 85245916cd2Sjpk } 85345916cd2Sjpk if (getpwuid_r(uid, &pw_ent, pw_buf, sizeof (pw_buf)) == NULL) 85445916cd2Sjpk return (-1); 85545916cd2Sjpk if (optflag & FORCE_ALL) 8567c478bd9Sstevel@tonic-gate mode = "-I"; 85745916cd2Sjpk else if (optflag & FORCE) 8587c478bd9Sstevel@tonic-gate mode = "-f"; 8597c478bd9Sstevel@tonic-gate else 8607c478bd9Sstevel@tonic-gate mode = "-s"; 86145916cd2Sjpk if (path == NULL) 86245916cd2Sjpk return (0); 8637c478bd9Sstevel@tonic-gate if ((cmd = strrchr(path, '/')) == NULL) 8647c478bd9Sstevel@tonic-gate cmd = path; 8657c478bd9Sstevel@tonic-gate else 8667c478bd9Sstevel@tonic-gate cmd++; /* skip leading '/' */ 8677c478bd9Sstevel@tonic-gate c = vfork(); 8687c478bd9Sstevel@tonic-gate switch (c) { 8697c478bd9Sstevel@tonic-gate case -1: 8707c478bd9Sstevel@tonic-gate return (-1); 8717c478bd9Sstevel@tonic-gate case 0: 8727c478bd9Sstevel@tonic-gate (void) setuid(0); 87345916cd2Sjpk if (system_labeled && (optflag & WINDOWING)) { 87445916cd2Sjpk /* First try .windowing version of script */ 87545916cd2Sjpk (void) strncpy(wdwpath, path, PATH_MAX); 87645916cd2Sjpk (void) strncat(wdwpath, ".windowing", PATH_MAX); 87745916cd2Sjpk if ((wdwcmd = strrchr(wdwpath, '/')) == NULL) 87845916cd2Sjpk wdwcmd = wdwpath; 87945916cd2Sjpk (void) execl(wdwpath, wdwcmd, mode, devname, clean_arg, 88045916cd2Sjpk pw_ent.pw_name, devzone, zonepath, NULL); 88145916cd2Sjpk /* If that failed, run regular version via dtterm */ 88245916cd2Sjpk (void) snprintf(title, sizeof (title), 88345916cd2Sjpk "Device %s for %s", 88445916cd2Sjpk strcmp(clean_arg, ALLOC_CLEAN) == 0 ? 88545916cd2Sjpk "allocation" : "deallocation", devname); 88645916cd2Sjpk (void) execl("/usr/dt/bin/dtterm", "dtterm", 88745916cd2Sjpk "-title", title, "-geometry", "x10+100+400", 88845916cd2Sjpk "-e", "/etc/security/lib/wdwwrapper", 88945916cd2Sjpk path, mode, devname, clean_arg, pw_ent.pw_name, 89045916cd2Sjpk devzone, zonepath, NULL); 89145916cd2Sjpk /* 89245916cd2Sjpk * And if that failed, continue on to try 89345916cd2Sjpk * running regular version directly. 89445916cd2Sjpk */ 89545916cd2Sjpk } 8967c478bd9Sstevel@tonic-gate dprintf("clean script: %s, ", path); 8977c478bd9Sstevel@tonic-gate dprintf("cmd=%s, ", cmd); 8987c478bd9Sstevel@tonic-gate dprintf("mode=%s, ", mode); 89945916cd2Sjpk if (system_labeled) { 90045916cd2Sjpk dprintf("devname=%s ", devname); 90145916cd2Sjpk dprintf("zonename=%s ", devzone); 90245916cd2Sjpk dprintf("zonepath=%s ", zonepath); 90345916cd2Sjpk dprintf("username=%s\n", pw_ent.pw_name); 90445916cd2Sjpk (void) execl(path, cmd, mode, devname, clean_arg, 90545916cd2Sjpk pw_ent.pw_name, devzone, zonepath, NULL); 90645916cd2Sjpk } else { 90745916cd2Sjpk dprintf("devname=%s\n", devname); 90845916cd2Sjpk (void) execle(path, cmd, mode, devname, NULL, newenv); 90945916cd2Sjpk } 9107c478bd9Sstevel@tonic-gate dprintf("Unable to execute clean up script %s\n", path); 9117c478bd9Sstevel@tonic-gate dperror(""); 91245916cd2Sjpk exit(CNTDEXECERR); 9137c478bd9Sstevel@tonic-gate default: 91445916cd2Sjpk (void) waitpid(c, &status, 0); 91545916cd2Sjpk dprintf("Child %d", c); 91645916cd2Sjpk if (WIFEXITED(status)) { 91745916cd2Sjpk exit_status = WEXITSTATUS(status); 91845916cd2Sjpk dprintf(" exited, status: %d\n", exit_status); 91945916cd2Sjpk return (exit_status); 92045916cd2Sjpk } else if (WIFSIGNALED(status)) { 92145916cd2Sjpk dprintf(" killed, signal %d\n", WTERMSIG(status)); 92245916cd2Sjpk } else { 92345916cd2Sjpk dprintf(": exit status %d\n", status); 92445916cd2Sjpk } 9257c478bd9Sstevel@tonic-gate return (-1); 9267c478bd9Sstevel@tonic-gate } 9277c478bd9Sstevel@tonic-gate } 9287c478bd9Sstevel@tonic-gate 92945916cd2Sjpk int 93045916cd2Sjpk _deallocate_dev(int optflag, devalloc_t *da, devmap_t *dm_in, uid_t uid, 93145916cd2Sjpk char *zonename) 9327c478bd9Sstevel@tonic-gate { 93345916cd2Sjpk int bytes = 0; 9347c478bd9Sstevel@tonic-gate int error = 0; 93545916cd2Sjpk int is_authorized = 0; 93645916cd2Sjpk uid_t nuid; 93745916cd2Sjpk char *fname = NULL; 93845916cd2Sjpk char file_name[MAXPATHLEN]; 93945916cd2Sjpk char *devzone = NULL; 94045916cd2Sjpk devmap_t *dm = NULL, *dm_new = NULL; 94145916cd2Sjpk struct stat stat_buf; 94245916cd2Sjpk struct state_file sf; 9437c478bd9Sstevel@tonic-gate 94445916cd2Sjpk if (dm_in == NULL) { 94545916cd2Sjpk setdmapent(); 94645916cd2Sjpk if ((dm_new = getdmapnam(da->da_devname)) == NULL) { 94745916cd2Sjpk enddmapent(); 94845916cd2Sjpk dprintf("Unable to find %s in device map database\n", 94945916cd2Sjpk da->da_devname); 95045916cd2Sjpk return (NODMAPERR); 95145916cd2Sjpk } 95245916cd2Sjpk enddmapent(); 95345916cd2Sjpk dm = dm_new; 95445916cd2Sjpk } else { 95545916cd2Sjpk dm = dm_in; 95645916cd2Sjpk } 95745916cd2Sjpk if (system_labeled) { 95845916cd2Sjpk if (_dev_file_name(&sf, dm) != 0) { 95945916cd2Sjpk if (dm_new) 96045916cd2Sjpk freedmapent(dm_new); 96145916cd2Sjpk dprintf("Unable to find %s device files\n", 96245916cd2Sjpk da->da_devname); 96345916cd2Sjpk error = NODMAPERR; 96445916cd2Sjpk goto out; 96545916cd2Sjpk } 96645916cd2Sjpk fname = sf.sf_path; 96745916cd2Sjpk } else { 96845916cd2Sjpk bytes = snprintf(file_name, MAXPATHLEN, "%s/%s", DAC_DIR, 96945916cd2Sjpk da->da_devname); 97045916cd2Sjpk if (bytes <= 0) { 97145916cd2Sjpk error = DEVNAMEERR; 97245916cd2Sjpk goto out; 97345916cd2Sjpk } else if (bytes >= MAXPATHLEN) { 97445916cd2Sjpk dprintf("device name %s is too long.\n", 97545916cd2Sjpk da->da_devname); 97645916cd2Sjpk error = DEVLONGERR; 97745916cd2Sjpk goto out; 97845916cd2Sjpk } 97945916cd2Sjpk fname = file_name; 9807c478bd9Sstevel@tonic-gate } 9817c478bd9Sstevel@tonic-gate 98245916cd2Sjpk audit_allocate_device(fname); 9837c478bd9Sstevel@tonic-gate 98445916cd2Sjpk if (stat(fname, &stat_buf) != 0) { 98545916cd2Sjpk dprintf("Unable to stat %s\n", fname); 98645916cd2Sjpk error = DACACCERR; 98745916cd2Sjpk goto out; 98845916cd2Sjpk } 98945916cd2Sjpk is_authorized = _is_dev_authorized(da, uid); 99045916cd2Sjpk if (!(optflag & (FORCE | FORCE_ALL)) && !is_authorized) { 99145916cd2Sjpk dprintf("User %d is unauthorized to deallocate\n", (int)uid); 99245916cd2Sjpk error = UAUTHERR; 99345916cd2Sjpk goto out; 99445916cd2Sjpk } 99545916cd2Sjpk if (system_labeled) { 99645916cd2Sjpk /* 99745916cd2Sjpk * unless we're here to deallocate by force, check if the 99845916cd2Sjpk * label at which the device is currently allocated is 99945916cd2Sjpk * within the user label range. 100045916cd2Sjpk */ 100145916cd2Sjpk if (!(optflag & FORCE) && 100245916cd2Sjpk _check_label(da, zonename, uid, CHECK_URANGE) != 0) { 100345916cd2Sjpk error = LABELRNGERR; 100445916cd2Sjpk goto out; 100545916cd2Sjpk } 100645916cd2Sjpk } 100745916cd2Sjpk if (!(optflag & FORCE) && stat_buf.st_uid != uid && 100845916cd2Sjpk DEV_ALLOCATED(stat_buf)) { 100945916cd2Sjpk error = ALLOCUERR; 101045916cd2Sjpk goto out; 101145916cd2Sjpk } 101245916cd2Sjpk if (!DEV_ALLOCATED(stat_buf)) { 101345916cd2Sjpk if (DEV_ERRORED(stat_buf)) { 101445916cd2Sjpk if (!(optflag & FORCE)) { 101545916cd2Sjpk error = DEVSTATEERR; 101645916cd2Sjpk goto out; 101745916cd2Sjpk } 101845916cd2Sjpk } else { 101945916cd2Sjpk error = DEVNALLOCERR; 102045916cd2Sjpk goto out; 102145916cd2Sjpk } 102245916cd2Sjpk } 102345916cd2Sjpk /* All checks passed, time to lock and deallocate */ 102445916cd2Sjpk if ((error = lock_dev(fname)) != 0) 102545916cd2Sjpk goto out; 102645916cd2Sjpk if (system_labeled) { 102745916cd2Sjpk devzone = kva_match(da->da_devopts, DAOPT_ZONE); 102845916cd2Sjpk if (devzone && (strcmp(devzone, GLOBAL_ZONENAME) != 0)) { 102945916cd2Sjpk if ((remove_znode(devzone, dm) != 0) && 103045916cd2Sjpk !(optflag & FORCE)) { 103145916cd2Sjpk error = ZONEERR; 103245916cd2Sjpk goto out; 103345916cd2Sjpk } 103445916cd2Sjpk } 103545916cd2Sjpk } 103645916cd2Sjpk if ((error = mk_unalloc(optflag, dm)) != 0) { 103745916cd2Sjpk if (!(optflag & FORCE)) 103845916cd2Sjpk goto out; 103945916cd2Sjpk } 104045916cd2Sjpk if (system_labeled == 0) { 104145916cd2Sjpk if ((error = _newdac(fname, ALLOC_UID, ALLOC_GID, 104245916cd2Sjpk DEALLOC_MODE)) != 0) { 104345916cd2Sjpk (void) _newdac(file_name, ALLOC_UID, ALLOC_GID, 104445916cd2Sjpk ALLOC_ERR_MODE); 104545916cd2Sjpk goto out; 104645916cd2Sjpk } 104745916cd2Sjpk } 104845916cd2Sjpk /* 104945916cd2Sjpk * if we are deallocating device owned by someone else, 105045916cd2Sjpk * pass the owner's uid to the cleaning script. 105145916cd2Sjpk */ 105245916cd2Sjpk nuid = (stat_buf.st_uid == uid) ? uid : stat_buf.st_uid; 105345916cd2Sjpk error = exec_clean(optflag, da->da_devname, da->da_devexec, nuid, 105445916cd2Sjpk devzone, DEALLOC_CLEAN); 105545916cd2Sjpk if (error != 0) { 105645916cd2Sjpk if (!(optflag & (FORCE | FORCE_ALL))) { 105745916cd2Sjpk error = CLEANERR; 105845916cd2Sjpk (void) mk_error(dm); 105945916cd2Sjpk } else { 106045916cd2Sjpk error = 0; 106145916cd2Sjpk } 106245916cd2Sjpk } 106345916cd2Sjpk 106445916cd2Sjpk out: 106545916cd2Sjpk if (dm_new) 106645916cd2Sjpk freedmapent(dm_new); 106745916cd2Sjpk return (error); 106845916cd2Sjpk } 106945916cd2Sjpk 107045916cd2Sjpk int 107145916cd2Sjpk _allocate_dev(int optflag, uid_t uid, devalloc_t *da, char *zonename) 107245916cd2Sjpk { 107345916cd2Sjpk int i; 107445916cd2Sjpk int bytes = 0; 107545916cd2Sjpk int error = 0; 107645916cd2Sjpk int is_authorized = 0; 107745916cd2Sjpk int dealloc_optflag = 0; 107845916cd2Sjpk char *fname = NULL; 107945916cd2Sjpk char file_name[MAXPATHLEN]; 108045916cd2Sjpk devmap_t *dm; 108145916cd2Sjpk struct stat stat_buf; 108245916cd2Sjpk struct state_file sf; 108345916cd2Sjpk struct zone_path zpath; 108445916cd2Sjpk 108545916cd2Sjpk zpath.count = 0; 108645916cd2Sjpk zpath.path = NULL; 108745916cd2Sjpk setdmapent(); 108845916cd2Sjpk if ((dm = getdmapnam(da->da_devname)) == NULL) { 108945916cd2Sjpk enddmapent(); 109045916cd2Sjpk dprintf("Unable to find %s in device map database\n", 109145916cd2Sjpk da->da_devname); 109245916cd2Sjpk return (NODMAPERR); 109345916cd2Sjpk } 109445916cd2Sjpk enddmapent(); 109545916cd2Sjpk if (system_labeled) { 109645916cd2Sjpk if (_dev_file_name(&sf, dm) != 0) { 109745916cd2Sjpk freedmapent(dm); 109845916cd2Sjpk dprintf("Unable to find %s device files\n", 109945916cd2Sjpk da->da_devname); 110045916cd2Sjpk error = NODMAPERR; 110145916cd2Sjpk goto out; 110245916cd2Sjpk } 110345916cd2Sjpk fname = sf.sf_path; 110445916cd2Sjpk } else { 110545916cd2Sjpk bytes = snprintf(file_name, MAXPATHLEN, "%s/%s", DAC_DIR, 110645916cd2Sjpk da->da_devname); 110745916cd2Sjpk if (bytes <= 0) { 110845916cd2Sjpk error = DEVNAMEERR; 110945916cd2Sjpk goto out; 111045916cd2Sjpk } else if (bytes >= MAXPATHLEN) { 111145916cd2Sjpk dprintf("device name %s is too long.\n", 111245916cd2Sjpk da->da_devname); 111345916cd2Sjpk error = DEVLONGERR; 111445916cd2Sjpk goto out; 111545916cd2Sjpk } 111645916cd2Sjpk fname = file_name; 111745916cd2Sjpk } 111845916cd2Sjpk 111945916cd2Sjpk (void) audit_allocate_device(fname); 112045916cd2Sjpk 112145916cd2Sjpk if (stat(fname, &stat_buf) != 0) { 112245916cd2Sjpk dprintf("Unable to stat %s\n", fname); 11237c478bd9Sstevel@tonic-gate dperror("Error:"); 112445916cd2Sjpk error = DACACCERR; 112545916cd2Sjpk goto out; 11267c478bd9Sstevel@tonic-gate } 112745916cd2Sjpk if (DEV_ERRORED(stat_buf)) { 112845916cd2Sjpk error = DEVSTATEERR; 112945916cd2Sjpk goto out; 113045916cd2Sjpk } 113145916cd2Sjpk is_authorized = _is_dev_authorized(da, uid); 113245916cd2Sjpk if (is_authorized == ALLOC_BY_NONE) { 113345916cd2Sjpk dprintf("Device %s is not allocatable\n", da->da_devname); 113445916cd2Sjpk error = UAUTHERR; 113545916cd2Sjpk goto out; 113645916cd2Sjpk } else if (!is_authorized && !(optflag & USERNAME)) { 113745916cd2Sjpk dprintf("User %d is unauthorized to allocate\n", (int)uid); 113845916cd2Sjpk error = UAUTHERR; 113945916cd2Sjpk goto out; 114045916cd2Sjpk } 114145916cd2Sjpk if (system_labeled) { 114245916cd2Sjpk /* 114345916cd2Sjpk * check if label of the zone to which the device is being 114445916cd2Sjpk * allocated is within the device label range. 114545916cd2Sjpk */ 114645916cd2Sjpk if (_check_label(da, zonename, uid, CHECK_DRANGE) != 0) { 114745916cd2Sjpk error = LABELRNGERR; 114845916cd2Sjpk goto out; 114945916cd2Sjpk } 115045916cd2Sjpk } 115145916cd2Sjpk if (check_devs(dm) == -1) { 115245916cd2Sjpk error = DSPMISSERR; 115345916cd2Sjpk goto out; 115445916cd2Sjpk } 11557c478bd9Sstevel@tonic-gate if (DEV_ALLOCATED(stat_buf)) { 115645916cd2Sjpk if (optflag & FORCE) { 115745916cd2Sjpk if (optflag & SILENT) 115845916cd2Sjpk dealloc_optflag = FORCE|SILENT; 115940e2b7c9Spaulson else 116045916cd2Sjpk dealloc_optflag = FORCE; 116145916cd2Sjpk if (_deallocate_dev(dealloc_optflag, da, dm, uid, 116245916cd2Sjpk zonename)) { 11637c478bd9Sstevel@tonic-gate dprintf("Couldn't force deallocate device %s\n", 116445916cd2Sjpk da->da_devname); 116545916cd2Sjpk error = CNTFRCERR; 116645916cd2Sjpk goto out; 11677c478bd9Sstevel@tonic-gate } 11687c478bd9Sstevel@tonic-gate } else if (stat_buf.st_uid == uid) { 116945916cd2Sjpk error = PREALLOCERR; 117045916cd2Sjpk goto out; 11717c478bd9Sstevel@tonic-gate } else { 117245916cd2Sjpk error = ALLOCUERR; 117345916cd2Sjpk goto out; 117445916cd2Sjpk } 117545916cd2Sjpk } 117645916cd2Sjpk /* All checks passed, time to lock and allocate */ 117745916cd2Sjpk if ((error = lock_dev(fname)) != 0) 117845916cd2Sjpk goto out; 117945916cd2Sjpk if (system_labeled) { 118045916cd2Sjpk /* 118145916cd2Sjpk * Run the cleaning program; it also mounts allocated 118245916cd2Sjpk * device if required. 118345916cd2Sjpk */ 118445916cd2Sjpk error = exec_clean(optflag, da->da_devname, da->da_devexec, uid, 118545916cd2Sjpk zonename, ALLOC_CLEAN); 118645916cd2Sjpk if ((error != 0) && (error != CLEAN_MOUNT)) { 118745916cd2Sjpk error = CLEANERR; 118845916cd2Sjpk (void) mk_error(dm); 118945916cd2Sjpk goto out; 119045916cd2Sjpk } 119145916cd2Sjpk /* 119245916cd2Sjpk * If not mounted, create zonelinks, if this is not the 119345916cd2Sjpk * global zone. 119445916cd2Sjpk */ 119545916cd2Sjpk if ((strcmp(zonename, GLOBAL_ZONENAME) != 0) && 119645916cd2Sjpk (error != CLEAN_MOUNT)) { 119745916cd2Sjpk if (create_znode(zonename, &zpath, dm) != 0) { 119845916cd2Sjpk error = ZONEERR; 119945916cd2Sjpk goto out; 120045916cd2Sjpk } 120145916cd2Sjpk } 120245916cd2Sjpk } 120345916cd2Sjpk 120445916cd2Sjpk (void) audit_allocate_list(dm->dmap_devlist); 120545916cd2Sjpk 120645916cd2Sjpk if ((error = mk_alloc(dm, uid, &zpath)) != 0) { 120745916cd2Sjpk (void) mk_unalloc(optflag, dm); 120845916cd2Sjpk goto out; 120945916cd2Sjpk } 121045916cd2Sjpk 121145916cd2Sjpk if (system_labeled == 0) { 121245916cd2Sjpk if ((error = _newdac(file_name, uid, getgid(), 121345916cd2Sjpk ALLOC_MODE)) != 0) { 121445916cd2Sjpk (void) _newdac(file_name, ALLOC_UID, ALLOC_GID, 121545916cd2Sjpk ALLOC_ERR_MODE); 121645916cd2Sjpk goto out; 121745916cd2Sjpk } 121845916cd2Sjpk } 121945916cd2Sjpk error = 0; 122045916cd2Sjpk out: 122145916cd2Sjpk if (zpath.count) { 122245916cd2Sjpk for (i = 0; i < zpath.count; i++) 122345916cd2Sjpk free(zpath.path[i]); 122445916cd2Sjpk free(zpath.path); 122545916cd2Sjpk } 122645916cd2Sjpk freedmapent(dm); 122745916cd2Sjpk return (error); 122845916cd2Sjpk } 122945916cd2Sjpk 123045916cd2Sjpk void 1231*facf4a8dSllai1 _store_devnames(int *count, struct dev_names *dnms, char *zonename, 123245916cd2Sjpk devalloc_t *da, int flag) 123345916cd2Sjpk { 123445916cd2Sjpk int i; 123545916cd2Sjpk 123645916cd2Sjpk dnms->dnames = (char **)realloc(dnms->dnames, 123745916cd2Sjpk (*count + 1) * sizeof (char *)); 123845916cd2Sjpk if (da) { 123945916cd2Sjpk dnms->dnames[*count] = strdup(da->da_devname); 124045916cd2Sjpk (*count)++; 124145916cd2Sjpk } else { 124245916cd2Sjpk dnms->dnames[*count] = NULL; 124345916cd2Sjpk if (flag == DA_ADD_ZONE) 124445916cd2Sjpk (void) update_device(dnms->dnames, zonename, 124545916cd2Sjpk DA_ADD_ZONE); 124645916cd2Sjpk else if (flag == DA_REMOVE_ZONE) 124745916cd2Sjpk (void) update_device(dnms->dnames, NULL, 124845916cd2Sjpk DA_REMOVE_ZONE); 124945916cd2Sjpk for (i = 0; i < *count; i++) 125045916cd2Sjpk free(dnms->dnames[i]); 125145916cd2Sjpk free(dnms->dnames); 125245916cd2Sjpk } 125345916cd2Sjpk } 125445916cd2Sjpk 125545916cd2Sjpk int 125645916cd2Sjpk allocate(int optflag, uid_t uid, char *device, char *zonename) 125745916cd2Sjpk { 125845916cd2Sjpk int count = 0; 125945916cd2Sjpk int error = 0; 126045916cd2Sjpk devalloc_t *da; 1261*facf4a8dSllai1 struct dev_names dnms; 126245916cd2Sjpk 126345916cd2Sjpk if (optflag & (FORCE | USERID | USERNAME)) { 126445916cd2Sjpk if (!_is_authorized(DEVICE_REVOKE_AUTH, getuid())) 126545916cd2Sjpk return (UAUTHERR); 126645916cd2Sjpk } 126745916cd2Sjpk dnms.dnames = NULL; 126845916cd2Sjpk setdaent(); 126945916cd2Sjpk if (optflag & TYPE) { 127045916cd2Sjpk /* 127145916cd2Sjpk * allocate devices of this type 127245916cd2Sjpk */ 127345916cd2Sjpk while ((da = getdatype(device)) != NULL) { 127445916cd2Sjpk if (system_labeled && 127545916cd2Sjpk da_check_logindevperm(da->da_devname)) { 127645916cd2Sjpk freedaent(da); 12777c478bd9Sstevel@tonic-gate continue; 12787c478bd9Sstevel@tonic-gate } 127945916cd2Sjpk dprintf("trying to allocate %s\n", da->da_devname); 128045916cd2Sjpk error = _allocate_dev(optflag, uid, da, zonename); 128145916cd2Sjpk if (system_labeled && (error == 0)) { 128245916cd2Sjpk /* 128345916cd2Sjpk * we need to record in device_allocate the 128445916cd2Sjpk * label (zone name) at which this device is 128545916cd2Sjpk * being allocated. store this device entry. 128645916cd2Sjpk */ 128745916cd2Sjpk _store_devnames(&count, &dnms, zonename, da, 0); 12887c478bd9Sstevel@tonic-gate } 128945916cd2Sjpk freedaent(da); 129045916cd2Sjpk error = 0; 12917c478bd9Sstevel@tonic-gate } 129245916cd2Sjpk } else { 129345916cd2Sjpk /* 129445916cd2Sjpk * allocate this device 129545916cd2Sjpk */ 129645916cd2Sjpk if ((da = getdanam(device)) == NULL) { 12977c478bd9Sstevel@tonic-gate enddaent(); 129845916cd2Sjpk return (NODAERR); 129945916cd2Sjpk } 130045916cd2Sjpk if (system_labeled && da_check_logindevperm(device)) { 130145916cd2Sjpk freedaent(da); 130245916cd2Sjpk return (LOGINDEVPERMERR); 130345916cd2Sjpk } 130445916cd2Sjpk dprintf("trying to allocate %s\n", da->da_devname); 130545916cd2Sjpk error = _allocate_dev(optflag, uid, da, zonename); 130645916cd2Sjpk /* 130745916cd2Sjpk * we need to record in device_allocate the label (zone name) 130845916cd2Sjpk * at which this device is being allocated. store this device 130945916cd2Sjpk * entry. 131045916cd2Sjpk */ 131145916cd2Sjpk if (system_labeled && (error == 0)) 131245916cd2Sjpk _store_devnames(&count, &dnms, zonename, da, 0); 131345916cd2Sjpk freedaent(da); 131445916cd2Sjpk } 131545916cd2Sjpk enddaent(); 131645916cd2Sjpk /* 131745916cd2Sjpk * add to device_allocate labels (zone names) for the devices we 131845916cd2Sjpk * allocated. 131945916cd2Sjpk */ 132045916cd2Sjpk if (dnms.dnames) 132145916cd2Sjpk _store_devnames(&count, &dnms, zonename, NULL, DA_ADD_ZONE); 132245916cd2Sjpk 13237c478bd9Sstevel@tonic-gate return (error); 13247c478bd9Sstevel@tonic-gate } 132545916cd2Sjpk 132645916cd2Sjpk /* ARGSUSED */ 132745916cd2Sjpk int 132845916cd2Sjpk deallocate(int optflag, uid_t uid, char *device, char *zonename) 132945916cd2Sjpk { 133045916cd2Sjpk int count = 0; 133145916cd2Sjpk int error = 0; 133245916cd2Sjpk devalloc_t *da; 1333*facf4a8dSllai1 struct dev_names dnms; 133445916cd2Sjpk 133545916cd2Sjpk if (optflag & (FORCE | FORCE_ALL)) { 133645916cd2Sjpk if (!_is_authorized(DEVICE_REVOKE_AUTH, getuid())) 133745916cd2Sjpk return (UAUTHERR); 133845916cd2Sjpk } 133945916cd2Sjpk if (optflag & FORCE_ALL) 134045916cd2Sjpk optflag |= FORCE; 134145916cd2Sjpk dnms.dnames = NULL; 134245916cd2Sjpk setdaent(); 134345916cd2Sjpk if (optflag & FORCE_ALL) { 134445916cd2Sjpk /* 134545916cd2Sjpk * deallocate all devices 134645916cd2Sjpk */ 134745916cd2Sjpk while ((da = getdaent()) != NULL) { 134845916cd2Sjpk if (system_labeled && 134945916cd2Sjpk da_check_logindevperm(da->da_devname)) { 135045916cd2Sjpk freedaent(da); 135145916cd2Sjpk continue; 135245916cd2Sjpk } 135345916cd2Sjpk dprintf("trying to deallocate %s\n", da->da_devname); 135445916cd2Sjpk error = _deallocate_dev(optflag, da, NULL, uid, 135545916cd2Sjpk zonename); 135645916cd2Sjpk if (system_labeled && (error == 0)) { 135745916cd2Sjpk /* 135845916cd2Sjpk * we need to remove this device's allocation 135945916cd2Sjpk * label (zone name) from device_allocate. 136045916cd2Sjpk * store this device name. 136145916cd2Sjpk */ 136245916cd2Sjpk _store_devnames(&count, &dnms, zonename, da, 0); 136345916cd2Sjpk } 136445916cd2Sjpk freedaent(da); 136545916cd2Sjpk error = 0; 136645916cd2Sjpk } 136745916cd2Sjpk } else if (system_labeled && optflag & TYPE) { 136845916cd2Sjpk /* 136945916cd2Sjpk * deallocate all devices of this type 137045916cd2Sjpk */ 137145916cd2Sjpk while ((da = getdatype(device)) != NULL) { 137245916cd2Sjpk if (da_check_logindevperm(da->da_devname)) { 137345916cd2Sjpk freedaent(da); 137445916cd2Sjpk continue; 137545916cd2Sjpk } 137645916cd2Sjpk dprintf("trying to deallocate %s\n", da->da_devname); 137745916cd2Sjpk error = _deallocate_dev(optflag, da, NULL, uid, 137845916cd2Sjpk zonename); 137945916cd2Sjpk if (error == 0) { 138045916cd2Sjpk /* 138145916cd2Sjpk * we need to remove this device's allocation 138245916cd2Sjpk * label (zone name) from device_allocate. 138345916cd2Sjpk * store this device name. 138445916cd2Sjpk */ 138545916cd2Sjpk _store_devnames(&count, &dnms, zonename, da, 0); 138645916cd2Sjpk } 138745916cd2Sjpk freedaent(da); 138845916cd2Sjpk error = 0; 138945916cd2Sjpk } 139045916cd2Sjpk } else if (!(optflag & TYPE)) { 139145916cd2Sjpk /* 139245916cd2Sjpk * deallocate this device 139345916cd2Sjpk */ 139445916cd2Sjpk if ((da = getdanam(device)) == NULL) { 139545916cd2Sjpk enddaent(); 139645916cd2Sjpk return (NODAERR); 139745916cd2Sjpk } 139845916cd2Sjpk if (system_labeled && da_check_logindevperm(da->da_devname)) { 139945916cd2Sjpk freedaent(da); 140045916cd2Sjpk return (LOGINDEVPERMERR); 140145916cd2Sjpk } 140245916cd2Sjpk dprintf("trying to deallocate %s\n", da->da_devname); 140345916cd2Sjpk error = _deallocate_dev(optflag, da, NULL, uid, zonename); 140445916cd2Sjpk if (system_labeled && (error == 0)) { 140545916cd2Sjpk /* 140645916cd2Sjpk * we need to remove this device's allocation label 140745916cd2Sjpk * (zone name) from device_allocate. store this 140845916cd2Sjpk * device name. 140945916cd2Sjpk */ 141045916cd2Sjpk _store_devnames(&count, &dnms, zonename, da, 0); 141145916cd2Sjpk } 141245916cd2Sjpk freedaent(da); 141345916cd2Sjpk } 141445916cd2Sjpk enddaent(); 141545916cd2Sjpk /* 141645916cd2Sjpk * remove from device_allocate labels (zone names) for the devices we 141745916cd2Sjpk * deallocated. 141845916cd2Sjpk */ 141945916cd2Sjpk if (dnms.dnames) 142045916cd2Sjpk _store_devnames(&count, &dnms, zonename, NULL, DA_REMOVE_ZONE); 142145916cd2Sjpk 142245916cd2Sjpk return (error); 142345916cd2Sjpk } 142445916cd2Sjpk 142545916cd2Sjpk static int 142645916cd2Sjpk _dev_file_name(struct state_file *sfp, devmap_t *dm) 142745916cd2Sjpk { 142845916cd2Sjpk sfp->sf_flags = 0; 142945916cd2Sjpk /* if devlist is generated, never leave device in error state */ 143045916cd2Sjpk if (dm->dmap_devlist[0] == '`') 143145916cd2Sjpk sfp->sf_flags |= SFF_NO_ERROR; 143245916cd2Sjpk if (dm->dmap_devarray == NULL || 143345916cd2Sjpk dm->dmap_devarray[0] == NULL) 143445916cd2Sjpk return (NODMAPERR); 143545916cd2Sjpk (void) strncpy(sfp->sf_path, dm->dmap_devarray[0], 143645916cd2Sjpk sizeof (sfp->sf_path)); 143745916cd2Sjpk sfp->sf_path[sizeof (sfp->sf_path) - 1] = '\0'; 143845916cd2Sjpk if (sfp->sf_path[0] == '\0') { 143945916cd2Sjpk dprintf("dev_file_name: no device list for %s\n", 144045916cd2Sjpk dm->dmap_devname); 144145916cd2Sjpk return (NODMAPERR); 144245916cd2Sjpk } 144345916cd2Sjpk 144445916cd2Sjpk return (0); 144545916cd2Sjpk } 144645916cd2Sjpk 144745916cd2Sjpk /* 144845916cd2Sjpk * _check_label - 144945916cd2Sjpk * checks the device label range against zone label, which is also 145045916cd2Sjpk * user's current label. 145145916cd2Sjpk * returns 0 if in range, -1 for all other conditions. 145245916cd2Sjpk * 145345916cd2Sjpk */ 145445916cd2Sjpk 145545916cd2Sjpk static int 145645916cd2Sjpk _check_label(devalloc_t *da, char *zonename, uid_t uid, int flag) 145745916cd2Sjpk { 145845916cd2Sjpk int err; 145945916cd2Sjpk int in_range = 0; 146045916cd2Sjpk char *alloczone, *lstr; 146145916cd2Sjpk char pw_buf[NSS_BUFLEN_PASSWD]; 146245916cd2Sjpk blrange_t *range; 146345916cd2Sjpk m_label_t *zlabel; 146445916cd2Sjpk struct passwd pw_ent; 146545916cd2Sjpk 146645916cd2Sjpk if ((da == NULL) || (zonename == NULL)) 146745916cd2Sjpk return (-1); 146845916cd2Sjpk 146945916cd2Sjpk if ((zlabel = getzonelabelbyname(zonename)) == NULL) { 147045916cd2Sjpk dprintf("unable to get label for %s zone\n", zonename); 147145916cd2Sjpk return (-1); 147245916cd2Sjpk } 147345916cd2Sjpk if (flag == CHECK_DRANGE) { 147445916cd2Sjpk blrange_t drange; 147545916cd2Sjpk 147645916cd2Sjpk drange.lower_bound = blabel_alloc(); 147745916cd2Sjpk lstr = kva_match(da->da_devopts, DAOPT_MINLABEL); 147845916cd2Sjpk if (lstr == NULL) { 147945916cd2Sjpk bsllow(drange.lower_bound); 148045916cd2Sjpk } else if (stobsl(lstr, drange.lower_bound, NO_CORRECTION, 148145916cd2Sjpk &err) == 0) { 148245916cd2Sjpk dprintf("bad min_label for device %s\n", 148345916cd2Sjpk da->da_devname); 148445916cd2Sjpk free(zlabel); 148545916cd2Sjpk blabel_free(drange.lower_bound); 148645916cd2Sjpk return (-1); 148745916cd2Sjpk } 148845916cd2Sjpk drange.upper_bound = blabel_alloc(); 148945916cd2Sjpk lstr = kva_match(da->da_devopts, DAOPT_MAXLABEL); 149045916cd2Sjpk if (lstr == NULL) { 149145916cd2Sjpk bslhigh(drange.upper_bound); 149245916cd2Sjpk } else if (stobsl(lstr, drange.upper_bound, NO_CORRECTION, 149345916cd2Sjpk &err) == 0) { 149445916cd2Sjpk dprintf("bad max_label for device %s\n", 149545916cd2Sjpk da->da_devname); 149645916cd2Sjpk free(zlabel); 149745916cd2Sjpk blabel_free(drange.lower_bound); 149845916cd2Sjpk blabel_free(drange.upper_bound); 149945916cd2Sjpk return (-1); 150045916cd2Sjpk } 150145916cd2Sjpk if (blinrange(zlabel, &drange) == 0) { 150245916cd2Sjpk char *zlbl = NULL, *min = NULL, *max = NULL; 150345916cd2Sjpk 150445916cd2Sjpk (void) bsltos(zlabel, &zlbl, 0, 0); 150545916cd2Sjpk (void) bsltos(drange.lower_bound, &min, 0, 0); 150645916cd2Sjpk (void) bsltos(drange.upper_bound, &max, 0, 0); 150745916cd2Sjpk dprintf("%s zone label ", zonename); 150845916cd2Sjpk dprintf("%s outside device label range: ", zlbl); 150945916cd2Sjpk dprintf("min - %s, ", min); 151045916cd2Sjpk dprintf("max - %s\n", max); 151145916cd2Sjpk free(zlabel); 151245916cd2Sjpk blabel_free(drange.lower_bound); 151345916cd2Sjpk blabel_free(drange.upper_bound); 151445916cd2Sjpk return (-1); 151545916cd2Sjpk } 151645916cd2Sjpk } else if (flag == CHECK_URANGE) { 151745916cd2Sjpk if (getpwuid_r(uid, &pw_ent, pw_buf, sizeof (pw_buf)) == NULL) { 151845916cd2Sjpk dprintf("Unable to get passwd entry for userid %d\n", 151945916cd2Sjpk (int)uid); 152045916cd2Sjpk free(zlabel); 152145916cd2Sjpk return (-1); 152245916cd2Sjpk } 152345916cd2Sjpk if ((range = getuserrange(pw_ent.pw_name)) == NULL) { 152445916cd2Sjpk dprintf("Unable to get label range for userid %d\n", 152545916cd2Sjpk (int)uid); 152645916cd2Sjpk free(zlabel); 152745916cd2Sjpk return (-1); 152845916cd2Sjpk } 152945916cd2Sjpk in_range = blinrange(zlabel, range); 153045916cd2Sjpk free(zlabel); 153145916cd2Sjpk blabel_free(range->lower_bound); 153245916cd2Sjpk blabel_free(range->upper_bound); 153345916cd2Sjpk free(range); 153445916cd2Sjpk if (in_range == 0) { 153545916cd2Sjpk dprintf("%s device label ", da->da_devname); 153645916cd2Sjpk dprintf("out of user %d label range\n", (int)uid); 153745916cd2Sjpk return (-1); 153845916cd2Sjpk } 153945916cd2Sjpk } else if (flag == CHECK_ZLABEL) { 154045916cd2Sjpk alloczone = kva_match(da->da_devopts, DAOPT_ZONE); 154145916cd2Sjpk if (alloczone == NULL) { 154245916cd2Sjpk free(zlabel); 154345916cd2Sjpk return (-1); 154445916cd2Sjpk } 154545916cd2Sjpk if (strcmp(zonename, alloczone) != 0) { 154645916cd2Sjpk dprintf("%s zone is different than ", zonename); 154745916cd2Sjpk dprintf("%s zone to which the device ", alloczone); 154845916cd2Sjpk dprintf("%s is allocated\n", da->da_devname); 154945916cd2Sjpk free(zlabel); 155045916cd2Sjpk return (-1); 155145916cd2Sjpk } 155245916cd2Sjpk } 155345916cd2Sjpk free(zlabel); 155445916cd2Sjpk 155545916cd2Sjpk return (0); 155645916cd2Sjpk } 155745916cd2Sjpk 155845916cd2Sjpk int 155945916cd2Sjpk create_znode(char *zonename, struct zone_path *zpath, devmap_t *list) 156045916cd2Sjpk { 156145916cd2Sjpk int size; 156245916cd2Sjpk int len = 0; 156345916cd2Sjpk int fcount = 0; 156445916cd2Sjpk char *p, *tmpfile, *zoneroot; 156545916cd2Sjpk char **file; 156645916cd2Sjpk char zonepath[MAXPATHLEN]; 1567*facf4a8dSllai1 di_prof_t prof = NULL; 156845916cd2Sjpk 156945916cd2Sjpk file = list->dmap_devarray; 157045916cd2Sjpk if (file == NULL) 157145916cd2Sjpk return (NODMAPERR); 157245916cd2Sjpk if ((zoneroot = getzonerootbyname(zonename)) == NULL) { 157345916cd2Sjpk dprintf("unable to get label for %s zone\n", zonename); 157445916cd2Sjpk return (1); 157545916cd2Sjpk } 157645916cd2Sjpk (void) strcpy(zonepath, zoneroot); 157745916cd2Sjpk free(zoneroot); 157845916cd2Sjpk len = strlen(zonepath); 157945916cd2Sjpk size = sizeof (zonepath); 1580*facf4a8dSllai1 (void) strlcat(zonepath, "/dev", size); 1581*facf4a8dSllai1 if (di_prof_init(zonepath, &prof)) { 1582*facf4a8dSllai1 dprintf("failed to initialize dev profile at %s\n", zonepath); 158345916cd2Sjpk return (1); 158445916cd2Sjpk } 1585*facf4a8dSllai1 zonepath[len] = '\0'; 1586*facf4a8dSllai1 for (; *file != NULL; file++) { 158745916cd2Sjpk /* 158845916cd2Sjpk * First time initialization 158945916cd2Sjpk */ 159045916cd2Sjpk tmpfile = strdup(*file); 159145916cd2Sjpk 159245916cd2Sjpk /* 159345916cd2Sjpk * Most devices have pathnames starting in /dev 159445916cd2Sjpk * but SunRay devices do not. In SRRS 3.1 they use /tmp. 159545916cd2Sjpk * 159645916cd2Sjpk * If the device pathname is not in /dev then create 159745916cd2Sjpk * a symbolic link to it and put the device in /dev 159845916cd2Sjpk */ 159945916cd2Sjpk if (strncmp(tmpfile, "/dev/", strlen("/dev/")) != 0) { 160045916cd2Sjpk char *linkdir; 160145916cd2Sjpk char srclinkdir[MAXPATHLEN]; 160245916cd2Sjpk char dstlinkdir[MAXPATHLEN]; 160345916cd2Sjpk 160445916cd2Sjpk linkdir = strchr(tmpfile + 1, '/'); 160545916cd2Sjpk p = strchr(linkdir + 1, '/'); 160645916cd2Sjpk *p = '\0'; 160745916cd2Sjpk (void) strcpy(dstlinkdir, "/dev"); 160845916cd2Sjpk (void) strncat(dstlinkdir, linkdir, MAXPATHLEN); 160945916cd2Sjpk (void) snprintf(srclinkdir, MAXPATHLEN, "%s/root%s", 161045916cd2Sjpk zonepath, tmpfile); 161145916cd2Sjpk (void) symlink(dstlinkdir, srclinkdir); 161245916cd2Sjpk *p = '/'; 161345916cd2Sjpk (void) strncat(dstlinkdir, p, MAXPATHLEN); 161445916cd2Sjpk free(tmpfile); 161545916cd2Sjpk tmpfile = strdup(dstlinkdir); 161645916cd2Sjpk } 1617*facf4a8dSllai1 if (di_prof_add_dev(prof, tmpfile)) { 1618*facf4a8dSllai1 dprintf("failed to add %s to profile\n", tmpfile); 1619*facf4a8dSllai1 di_prof_fini(prof); 162045916cd2Sjpk return (1); 162145916cd2Sjpk } 162245916cd2Sjpk if (strlcat(zonepath, tmpfile, size) >= size) { 162345916cd2Sjpk dprintf("Buffer overflow in create_znode for %s\n", 162445916cd2Sjpk *file); 162545916cd2Sjpk free(tmpfile); 1626*facf4a8dSllai1 di_prof_fini(prof); 162745916cd2Sjpk return (1); 162845916cd2Sjpk } 162945916cd2Sjpk free(tmpfile); 163045916cd2Sjpk fcount++; 163145916cd2Sjpk if ((zpath->path = (char **)realloc(zpath->path, 1632*facf4a8dSllai1 (fcount * sizeof (char *)))) == NULL) { 1633*facf4a8dSllai1 di_prof_fini(prof); 163445916cd2Sjpk return (1); 1635*facf4a8dSllai1 } 163645916cd2Sjpk zpath->path[zpath->count] = strdup(zonepath); 163745916cd2Sjpk zpath->count = fcount; 163845916cd2Sjpk zonepath[len] = '\0'; 163945916cd2Sjpk } 164045916cd2Sjpk 1641*facf4a8dSllai1 if (di_prof_commit(prof)) 1642*facf4a8dSllai1 dprintf("failed to add devices to zone %s\n", zonename); 1643*facf4a8dSllai1 di_prof_fini(prof); 1644*facf4a8dSllai1 164545916cd2Sjpk return (0); 164645916cd2Sjpk } 164745916cd2Sjpk 164845916cd2Sjpk int 164945916cd2Sjpk remove_znode(char *zonename, devmap_t *dm) 165045916cd2Sjpk { 165145916cd2Sjpk int len = 0; 165245916cd2Sjpk char *zoneroot; 165345916cd2Sjpk char **file; 165445916cd2Sjpk char zonepath[MAXPATHLEN]; 1655*facf4a8dSllai1 di_prof_t prof = NULL; 165645916cd2Sjpk 165745916cd2Sjpk file = dm->dmap_devarray; 165845916cd2Sjpk if (file == NULL) 165945916cd2Sjpk return (NODMAPERR); 166045916cd2Sjpk if ((zoneroot = getzonerootbyname(zonename)) == NULL) { 166145916cd2Sjpk (void) snprintf(zonepath, MAXPATHLEN, "/zone/%s", zonename); 166245916cd2Sjpk } else { 166345916cd2Sjpk (void) strcpy(zonepath, zoneroot); 166445916cd2Sjpk free(zoneroot); 166545916cd2Sjpk } 166645916cd2Sjpk /* 166745916cd2Sjpk * To support SunRay we will just deal with the 166845916cd2Sjpk * file in /dev, not the symlinks. 166945916cd2Sjpk */ 167045916cd2Sjpk (void) strncat(zonepath, "/dev", MAXPATHLEN); 167145916cd2Sjpk len = strlen(zonepath); 1672*facf4a8dSllai1 if (di_prof_init(zonepath, &prof)) { 1673*facf4a8dSllai1 dprintf("failed to initialize dev profile at %s\n", zonepath); 1674*facf4a8dSllai1 return (1); 1675*facf4a8dSllai1 } 167645916cd2Sjpk for (; *file != NULL; file++) { 167745916cd2Sjpk char *devrelpath; 167845916cd2Sjpk 167945916cd2Sjpk /* 168045916cd2Sjpk * remove device node from zone. 168145916cd2Sjpk * 168245916cd2Sjpk * SunRay devices don't start with /dev 168345916cd2Sjpk * so skip over first directory to make 168445916cd2Sjpk * sure it is /dev. SunRay devices in zones 168545916cd2Sjpk * will have a symlink into /dev but 168645916cd2Sjpk * we don't ever delete it. 168745916cd2Sjpk */ 168845916cd2Sjpk devrelpath = strchr(*file + 1, '/'); 168945916cd2Sjpk 1690*facf4a8dSllai1 if (di_prof_add_exclude(prof, devrelpath + 1)) { 1691*facf4a8dSllai1 dprintf("Failed exclude %s in dev profile\n", *file); 1692*facf4a8dSllai1 di_prof_fini(prof); 169345916cd2Sjpk return (1); 169445916cd2Sjpk } 169545916cd2Sjpk zonepath[len] = '\0'; 169645916cd2Sjpk } 169745916cd2Sjpk 1698*facf4a8dSllai1 if (di_prof_commit(prof)) 1699*facf4a8dSllai1 dprintf("failed to remove devices from zone %s\n", zonename); 1700*facf4a8dSllai1 di_prof_fini(prof); 170145916cd2Sjpk return (0); 170245916cd2Sjpk } 170345916cd2Sjpk 170445916cd2Sjpk int 170545916cd2Sjpk update_device(char **devnames, char *zonename, int flag) 170645916cd2Sjpk { 170745916cd2Sjpk int len, rc; 170845916cd2Sjpk char *optstr = NULL; 170945916cd2Sjpk da_args dargs; 171045916cd2Sjpk devinfo_t devinfo; 171145916cd2Sjpk 171245916cd2Sjpk dargs.optflag = flag; 171345916cd2Sjpk dargs.optflag |= DA_UPDATE|DA_ALLOC_ONLY; 171445916cd2Sjpk dargs.rootdir = NULL; 171545916cd2Sjpk dargs.devnames = devnames; 171645916cd2Sjpk devinfo.devname = devinfo.devtype = devinfo.devauths = devinfo.devexec = 171745916cd2Sjpk devinfo.devlist = NULL; 171845916cd2Sjpk if (dargs.optflag & DA_ADD_ZONE) { 171945916cd2Sjpk len = strlen(DAOPT_ZONE) + strlen(zonename) + 3; 172045916cd2Sjpk if ((optstr = (char *)malloc(len)) == NULL) 172145916cd2Sjpk return (-1); 172245916cd2Sjpk (void) snprintf(optstr, len, "%s%s%s", DAOPT_ZONE, KV_ASSIGN, 172345916cd2Sjpk zonename); 172445916cd2Sjpk devinfo.devopts = optstr; 172545916cd2Sjpk } 172645916cd2Sjpk dargs.devinfo = &devinfo; 172745916cd2Sjpk 172845916cd2Sjpk rc = da_update_device(&dargs); 172945916cd2Sjpk 173045916cd2Sjpk if (optstr) 173145916cd2Sjpk free(optstr); 173245916cd2Sjpk 173345916cd2Sjpk return (rc); 173445916cd2Sjpk } 1735