10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52311Sseb  * Common Development and Distribution License (the "License").
62311Sseb  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
223448Sdh155122  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <unistd.h>
290Sstevel@tonic-gate #include <stropts.h>
300Sstevel@tonic-gate #include <errno.h>
313147Sxc151355 #include <fcntl.h>
323147Sxc151355 #include <strings.h>
333147Sxc151355 #include <dirent.h>
343147Sxc151355 #include <sys/stat.h>
35*3871Syz147064 #include <libdladm.h>
363147Sxc151355 #include <libdladm_impl.h>
373184Smeem #include <libintl.h>
38733Skrgopi 
393147Sxc151355 static char		dladm_rootdir[MAXPATHLEN] = "/";
403147Sxc151355 
410Sstevel@tonic-gate /*
420Sstevel@tonic-gate  * Issue an ioctl to the specified file descriptor attached to the
430Sstevel@tonic-gate  * DLD control driver interface.
440Sstevel@tonic-gate  */
453147Sxc151355 int
46269Sericheng i_dladm_ioctl(int fd, int ic_cmd, void *ic_dp, int ic_len)
470Sstevel@tonic-gate {
480Sstevel@tonic-gate 	struct strioctl	iocb;
490Sstevel@tonic-gate 
500Sstevel@tonic-gate 	iocb.ic_cmd = ic_cmd;
510Sstevel@tonic-gate 	iocb.ic_timout = 0;
520Sstevel@tonic-gate 	iocb.ic_len = ic_len;
53269Sericheng 	iocb.ic_dp = (char *)ic_dp;
540Sstevel@tonic-gate 
550Sstevel@tonic-gate 	return (ioctl(fd, I_STR, &iocb));
560Sstevel@tonic-gate }
570Sstevel@tonic-gate 
583147Sxc151355 const char *
593147Sxc151355 dladm_status2str(dladm_status_t status, char *buf)
603147Sxc151355 {
613147Sxc151355 	const char	*s;
623147Sxc151355 
633147Sxc151355 	switch (status) {
643147Sxc151355 	case DLADM_STATUS_OK:
653147Sxc151355 		s = "ok";
663147Sxc151355 		break;
673147Sxc151355 	case DLADM_STATUS_BADARG:
683147Sxc151355 		s = "invalid argument";
693147Sxc151355 		break;
703147Sxc151355 	case DLADM_STATUS_FAILED:
713147Sxc151355 		s = "operation failed";
723147Sxc151355 		break;
733147Sxc151355 	case DLADM_STATUS_TOOSMALL:
743147Sxc151355 		s = "buffer size too small";
753147Sxc151355 		break;
763147Sxc151355 	case DLADM_STATUS_NOTSUP:
773147Sxc151355 		s = "operation not supported";
783147Sxc151355 		break;
793147Sxc151355 	case DLADM_STATUS_NOTFOUND:
803147Sxc151355 		s = "object not found";
813147Sxc151355 		break;
823147Sxc151355 	case DLADM_STATUS_BADVAL:
833147Sxc151355 		s = "invalid value";
843147Sxc151355 		break;
853147Sxc151355 	case DLADM_STATUS_NOMEM:
863147Sxc151355 		s = "insufficient memory";
873147Sxc151355 		break;
883147Sxc151355 	case DLADM_STATUS_EXIST:
893147Sxc151355 		s = "object already exists";
903147Sxc151355 		break;
913147Sxc151355 	case DLADM_STATUS_LINKINVAL:
923147Sxc151355 		s = "invalid link";
933147Sxc151355 		break;
943147Sxc151355 	case DLADM_STATUS_PROPRDONLY:
953147Sxc151355 		s = "read-only property";
963147Sxc151355 		break;
973147Sxc151355 	case DLADM_STATUS_BADVALCNT:
983147Sxc151355 		s = "invalid number of values";
993147Sxc151355 		break;
1003147Sxc151355 	case DLADM_STATUS_DBNOTFOUND:
1013147Sxc151355 		s = "database not found";
1023147Sxc151355 		break;
1033147Sxc151355 	case DLADM_STATUS_DENIED:
1043147Sxc151355 		s = "permission denied";
1053147Sxc151355 		break;
1063147Sxc151355 	case DLADM_STATUS_IOERR:
1073147Sxc151355 		s = "I/O error";
1083147Sxc151355 		break;
1093448Sdh155122 	case DLADM_STATUS_TEMPONLY:
1103448Sdh155122 		s = "change cannot be persistent, specify -t please";
1113448Sdh155122 		break;
112*3871Syz147064 	case DLADM_STATUS_TIMEDOUT:
113*3871Syz147064 		s = "operation timed out";
114*3871Syz147064 		break;
115*3871Syz147064 	case DLADM_STATUS_ISCONN:
116*3871Syz147064 		s = "already connected";
117*3871Syz147064 		break;
118*3871Syz147064 	case DLADM_STATUS_NOTCONN:
119*3871Syz147064 		s = "not connected";
120*3871Syz147064 		break;
121*3871Syz147064 	case DLADM_STATUS_REPOSITORYINVAL:
122*3871Syz147064 		s = "invalid configuration repository";
123*3871Syz147064 		break;
124*3871Syz147064 	case DLADM_STATUS_MACADDRINVAL:
125*3871Syz147064 		s = "invalid MAC address";
126*3871Syz147064 		break;
127*3871Syz147064 	case DLADM_STATUS_KEYINVAL:
128*3871Syz147064 		s = "invalid key";
129*3871Syz147064 		break;
1303147Sxc151355 	default:
1313184Smeem 		s = "<unknown error>";
1323184Smeem 		break;
1333147Sxc151355 	}
1343184Smeem 	(void) snprintf(buf, DLADM_STRSIZE, "%s", dgettext(TEXT_DOMAIN, s));
1353147Sxc151355 	return (buf);
1363147Sxc151355 }
1373147Sxc151355 
1383147Sxc151355 /*
1393147Sxc151355  * Convert a unix errno to a dladm_status_t.
1403147Sxc151355  * We only convert errnos that are likely to be encountered. All others
1413147Sxc151355  * are mapped to DLADM_STATUS_FAILED.
1423147Sxc151355  */
1433147Sxc151355 dladm_status_t
1443147Sxc151355 dladm_errno2status(int err)
1453147Sxc151355 {
1463147Sxc151355 	switch (err) {
1473147Sxc151355 	case EINVAL:
1483147Sxc151355 		return (DLADM_STATUS_BADARG);
1493147Sxc151355 	case EEXIST:
1503147Sxc151355 		return (DLADM_STATUS_EXIST);
1513147Sxc151355 	case ENOENT:
1523147Sxc151355 		return (DLADM_STATUS_NOTFOUND);
1533147Sxc151355 	case ENOSPC:
1543147Sxc151355 		return (DLADM_STATUS_TOOSMALL);
1553147Sxc151355 	case ENOMEM:
1563147Sxc151355 		return (DLADM_STATUS_NOMEM);
1573147Sxc151355 	case ENOTSUP:
1583147Sxc151355 		return (DLADM_STATUS_NOTSUP);
1593147Sxc151355 	case EACCES:
1603147Sxc151355 		return (DLADM_STATUS_DENIED);
1613147Sxc151355 	case EIO:
1623147Sxc151355 		return (DLADM_STATUS_IOERR);
1633147Sxc151355 	default:
1643147Sxc151355 		return (DLADM_STATUS_FAILED);
1653147Sxc151355 	}
1663147Sxc151355 }
1673147Sxc151355 
1683147Sxc151355 /*
1693147Sxc151355  * These are the uid and gid of the user 'dladm'.
1703147Sxc151355  * The directory /etc/dladm and all files under it are owned by this user.
1713147Sxc151355  */
1723147Sxc151355 #define	DLADM_DB_OWNER		15
1733147Sxc151355 #define	DLADM_DB_GROUP		3
1743147Sxc151355 #define	LOCK_DB_PERMS		S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
1753147Sxc151355 
1763147Sxc151355 static int
1773147Sxc151355 i_dladm_lock_db(const char *lock_file, short type)
1783147Sxc151355 {
1793147Sxc151355 	int	lock_fd;
1803147Sxc151355 	struct  flock lock;
1813147Sxc151355 
1823147Sxc151355 	if ((lock_fd = open(lock_file, O_RDWR | O_CREAT | O_TRUNC,
1833147Sxc151355 	    LOCK_DB_PERMS)) < 0)
1843147Sxc151355 		return (-1);
1853147Sxc151355 
1863147Sxc151355 	lock.l_type = type;
1873147Sxc151355 	lock.l_whence = SEEK_SET;
1883147Sxc151355 	lock.l_start = 0;
1893147Sxc151355 	lock.l_len = 0;
1903147Sxc151355 
1913147Sxc151355 	if (fcntl(lock_fd, F_SETLKW, &lock) < 0) {
1923147Sxc151355 		int err = errno;
1933147Sxc151355 
1943147Sxc151355 		(void) close(lock_fd);
1953147Sxc151355 		(void) unlink(lock_file);
1963147Sxc151355 		errno = err;
1973147Sxc151355 		return (-1);
1983147Sxc151355 	}
1993147Sxc151355 	return (lock_fd);
2003147Sxc151355 }
2013147Sxc151355 
2023147Sxc151355 static void
2033147Sxc151355 i_dladm_unlock_db(const char *lock_file, int fd)
2043147Sxc151355 {
2053147Sxc151355 	struct flock lock;
2063147Sxc151355 
2073147Sxc151355 	if (fd < 0)
2083147Sxc151355 		return;
2093147Sxc151355 
2103147Sxc151355 	lock.l_type = F_UNLCK;
2113147Sxc151355 	lock.l_whence = SEEK_SET;
2123147Sxc151355 	lock.l_start = 0;
2133147Sxc151355 	lock.l_len = 0;
2143147Sxc151355 
2153147Sxc151355 	(void) fcntl(fd, F_SETLKW, &lock);
2163147Sxc151355 	(void) close(fd);
2173147Sxc151355 	(void) unlink(lock_file);
2183147Sxc151355 }
2193147Sxc151355 
2203147Sxc151355 dladm_status_t
2213147Sxc151355 i_dladm_rw_db(const char *db_file, mode_t db_perms,
2223147Sxc151355     dladm_status_t (*process_db)(void *, FILE *, FILE *),
2233147Sxc151355     void *arg, boolean_t writeop)
2243147Sxc151355 {
2253147Sxc151355 	dladm_status_t	status = DLADM_STATUS_OK;
2263147Sxc151355 	FILE		*fp, *nfp = NULL;
2273147Sxc151355 	char		lock[MAXPATHLEN];
2283147Sxc151355 	char		file[MAXPATHLEN];
2293147Sxc151355 	char		newfile[MAXPATHLEN];
2303147Sxc151355 	char		*db_basename;
2313147Sxc151355 	int		nfd, lock_fd;
2323147Sxc151355 
2333147Sxc151355 	/*
2343147Sxc151355 	 * If we are called from a boot script such as net-physical,
2353147Sxc151355 	 * it's quite likely that the root fs is still not writable.
2363147Sxc151355 	 * For this case, it's ok for the lock creation to fail since
2373147Sxc151355 	 * no one else could be accessing our configuration file.
2383147Sxc151355 	 */
2393147Sxc151355 	db_basename = strrchr(db_file, '/');
2403147Sxc151355 	if (db_basename == NULL || db_basename[1] == '\0')
2413147Sxc151355 		return (dladm_errno2status(EINVAL));
2423147Sxc151355 	db_basename++;
2433147Sxc151355 	(void) snprintf(lock, MAXPATHLEN, "/tmp/%s.lock", db_basename);
2443147Sxc151355 	if ((lock_fd = i_dladm_lock_db
2453147Sxc151355 	    (lock, (writeop ? F_WRLCK : F_RDLCK))) < 0 && errno != EROFS)
2463147Sxc151355 		return (dladm_errno2status(errno));
2473147Sxc151355 
2483147Sxc151355 	(void) snprintf(file, MAXPATHLEN, "%s/%s", dladm_rootdir, db_file);
2493147Sxc151355 	if ((fp = fopen(file, (writeop ? "r+" : "r"))) == NULL) {
2503147Sxc151355 		int	err = errno;
2513147Sxc151355 
2523147Sxc151355 		i_dladm_unlock_db(lock, lock_fd);
2533147Sxc151355 		if (err == ENOENT)
2543147Sxc151355 			return (DLADM_STATUS_DBNOTFOUND);
2553147Sxc151355 
2563147Sxc151355 		return (dladm_errno2status(err));
2573147Sxc151355 	}
2583147Sxc151355 
2593147Sxc151355 	if (writeop) {
2603147Sxc151355 		(void) snprintf(newfile, MAXPATHLEN, "%s/%s.new",
2613147Sxc151355 		    dladm_rootdir, db_file);
2623147Sxc151355 		if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC,
2633147Sxc151355 		    db_perms)) < 0) {
2643147Sxc151355 			(void) fclose(fp);
2653147Sxc151355 			i_dladm_unlock_db(lock, lock_fd);
2663147Sxc151355 			return (dladm_errno2status(errno));
2673147Sxc151355 		}
2683147Sxc151355 
2693147Sxc151355 		if ((nfp = fdopen(nfd, "w")) == NULL) {
2703147Sxc151355 			(void) close(nfd);
2713147Sxc151355 			(void) fclose(fp);
2723147Sxc151355 			(void) unlink(newfile);
2733147Sxc151355 			i_dladm_unlock_db(lock, lock_fd);
2743147Sxc151355 			return (dladm_errno2status(errno));
2753147Sxc151355 		}
2763147Sxc151355 	}
2773147Sxc151355 	status = (*process_db)(arg, fp, nfp);
2783147Sxc151355 	if (!writeop || status != DLADM_STATUS_OK)
2793147Sxc151355 		goto done;
2803147Sxc151355 
2813147Sxc151355 	/*
2823147Sxc151355 	 * Configuration files need to be owned by the 'dladm' user.
2833147Sxc151355 	 * If we are invoked by root, the file ownership needs to be fixed.
2843147Sxc151355 	 */
2853147Sxc151355 	if (getuid() == 0 || geteuid() == 0) {
2863147Sxc151355 		if (fchown(nfd, DLADM_DB_OWNER, DLADM_DB_GROUP) < 0) {
2873147Sxc151355 			status = dladm_errno2status(errno);
2883147Sxc151355 			goto done;
2893147Sxc151355 		}
2903147Sxc151355 	}
2913147Sxc151355 
2923147Sxc151355 	if (fflush(nfp) == EOF) {
2933147Sxc151355 		status = dladm_errno2status(errno);
2943147Sxc151355 		goto done;
2953147Sxc151355 	}
2963147Sxc151355 	(void) fclose(fp);
2973147Sxc151355 	(void) fclose(nfp);
2983147Sxc151355 
2993147Sxc151355 	if (rename(newfile, file) < 0) {
3003147Sxc151355 		(void) unlink(newfile);
3013147Sxc151355 		i_dladm_unlock_db(lock, lock_fd);
3023147Sxc151355 		return (dladm_errno2status(errno));
3033147Sxc151355 	}
3043147Sxc151355 
3053147Sxc151355 	i_dladm_unlock_db(lock, lock_fd);
3063147Sxc151355 	return (DLADM_STATUS_OK);
3073147Sxc151355 
3083147Sxc151355 done:
3093147Sxc151355 	if (nfp != NULL) {
3103147Sxc151355 		(void) fclose(nfp);
3113147Sxc151355 		if (status != DLADM_STATUS_OK)
3123147Sxc151355 			(void) unlink(newfile);
3133147Sxc151355 	}
3143147Sxc151355 	(void) fclose(fp);
3153147Sxc151355 	i_dladm_unlock_db(lock, lock_fd);
3163147Sxc151355 	return (status);
3173147Sxc151355 }
3183147Sxc151355 
3193147Sxc151355 dladm_status_t
3203147Sxc151355 dladm_set_rootdir(const char *rootdir)
3213147Sxc151355 {
3223147Sxc151355 	DIR	*dp;
3233147Sxc151355 
3243147Sxc151355 	if (rootdir == NULL || *rootdir != '/' ||
3253147Sxc151355 	    (dp = opendir(rootdir)) == NULL)
3263147Sxc151355 		return (DLADM_STATUS_BADARG);
3273147Sxc151355 
3283147Sxc151355 	(void) strncpy(dladm_rootdir, rootdir, MAXPATHLEN);
3293147Sxc151355 	(void) closedir(dp);
3303147Sxc151355 	return (DLADM_STATUS_OK);
3313147Sxc151355 }
332