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 /* 225895Syz147064 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #include <unistd.h> 270Sstevel@tonic-gate #include <errno.h> 285895Syz147064 #include <ctype.h> 293147Sxc151355 #include <fcntl.h> 303147Sxc151355 #include <strings.h> 313147Sxc151355 #include <dirent.h> 326173Syz147064 #include <sys/param.h> 333147Sxc151355 #include <sys/stat.h> 343147Sxc151355 #include <libdladm_impl.h> 353184Smeem #include <libintl.h> 365895Syz147064 #include <libdlpi.h> 37733Skrgopi 383147Sxc151355 static char dladm_rootdir[MAXPATHLEN] = "/"; 393147Sxc151355 403147Sxc151355 const char * 413147Sxc151355 dladm_status2str(dladm_status_t status, char *buf) 423147Sxc151355 { 433147Sxc151355 const char *s; 443147Sxc151355 453147Sxc151355 switch (status) { 463147Sxc151355 case DLADM_STATUS_OK: 473147Sxc151355 s = "ok"; 483147Sxc151355 break; 493147Sxc151355 case DLADM_STATUS_BADARG: 503147Sxc151355 s = "invalid argument"; 513147Sxc151355 break; 523147Sxc151355 case DLADM_STATUS_FAILED: 533147Sxc151355 s = "operation failed"; 543147Sxc151355 break; 553147Sxc151355 case DLADM_STATUS_TOOSMALL: 563147Sxc151355 s = "buffer size too small"; 573147Sxc151355 break; 583147Sxc151355 case DLADM_STATUS_NOTSUP: 593147Sxc151355 s = "operation not supported"; 603147Sxc151355 break; 613147Sxc151355 case DLADM_STATUS_NOTFOUND: 623147Sxc151355 s = "object not found"; 633147Sxc151355 break; 643147Sxc151355 case DLADM_STATUS_BADVAL: 653147Sxc151355 s = "invalid value"; 663147Sxc151355 break; 673147Sxc151355 case DLADM_STATUS_NOMEM: 683147Sxc151355 s = "insufficient memory"; 693147Sxc151355 break; 703147Sxc151355 case DLADM_STATUS_EXIST: 713147Sxc151355 s = "object already exists"; 723147Sxc151355 break; 733147Sxc151355 case DLADM_STATUS_LINKINVAL: 743147Sxc151355 s = "invalid link"; 753147Sxc151355 break; 763147Sxc151355 case DLADM_STATUS_PROPRDONLY: 773147Sxc151355 s = "read-only property"; 783147Sxc151355 break; 793147Sxc151355 case DLADM_STATUS_BADVALCNT: 803147Sxc151355 s = "invalid number of values"; 813147Sxc151355 break; 823147Sxc151355 case DLADM_STATUS_DBNOTFOUND: 833147Sxc151355 s = "database not found"; 843147Sxc151355 break; 853147Sxc151355 case DLADM_STATUS_DENIED: 863147Sxc151355 s = "permission denied"; 873147Sxc151355 break; 883147Sxc151355 case DLADM_STATUS_IOERR: 893147Sxc151355 s = "I/O error"; 903147Sxc151355 break; 913448Sdh155122 case DLADM_STATUS_TEMPONLY: 923448Sdh155122 s = "change cannot be persistent, specify -t please"; 933448Sdh155122 break; 943871Syz147064 case DLADM_STATUS_TIMEDOUT: 953871Syz147064 s = "operation timed out"; 963871Syz147064 break; 973871Syz147064 case DLADM_STATUS_ISCONN: 983871Syz147064 s = "already connected"; 993871Syz147064 break; 1003871Syz147064 case DLADM_STATUS_NOTCONN: 1013871Syz147064 s = "not connected"; 1023871Syz147064 break; 1033871Syz147064 case DLADM_STATUS_REPOSITORYINVAL: 1043871Syz147064 s = "invalid configuration repository"; 1053871Syz147064 break; 1063871Syz147064 case DLADM_STATUS_MACADDRINVAL: 1073871Syz147064 s = "invalid MAC address"; 1083871Syz147064 break; 1093871Syz147064 case DLADM_STATUS_KEYINVAL: 1103871Syz147064 s = "invalid key"; 1113871Syz147064 break; 1125084Sjohnlev case DLADM_STATUS_INVALIDMACADDRLEN: 1135084Sjohnlev s = "invalid MAC address length"; 1145084Sjohnlev break; 1155084Sjohnlev case DLADM_STATUS_INVALIDMACADDRTYPE: 1165084Sjohnlev s = "invalid MAC address type"; 1175084Sjohnlev break; 1185895Syz147064 case DLADM_STATUS_LINKBUSY: 1195895Syz147064 s = "link busy"; 1205895Syz147064 break; 1215895Syz147064 case DLADM_STATUS_VIDINVAL: 1225895Syz147064 s = "invalid VLAN identifier"; 1235084Sjohnlev break; 1245895Syz147064 case DLADM_STATUS_TRYAGAIN: 1255895Syz147064 s = "try again later"; 1265084Sjohnlev break; 1275895Syz147064 case DLADM_STATUS_NONOTIF: 1285895Syz147064 s = "link notification is not supported"; 1295084Sjohnlev 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) { 1475903Ssowmini case 0: 1485903Ssowmini return (DLADM_STATUS_OK); 1493147Sxc151355 case EINVAL: 1503147Sxc151355 return (DLADM_STATUS_BADARG); 1513147Sxc151355 case EEXIST: 1523147Sxc151355 return (DLADM_STATUS_EXIST); 1533147Sxc151355 case ENOENT: 1543147Sxc151355 return (DLADM_STATUS_NOTFOUND); 1553147Sxc151355 case ENOSPC: 1563147Sxc151355 return (DLADM_STATUS_TOOSMALL); 1573147Sxc151355 case ENOMEM: 1583147Sxc151355 return (DLADM_STATUS_NOMEM); 1593147Sxc151355 case ENOTSUP: 1603147Sxc151355 return (DLADM_STATUS_NOTSUP); 1615895Syz147064 case ENETDOWN: 1625895Syz147064 return (DLADM_STATUS_NONOTIF); 1633147Sxc151355 case EACCES: 164*7408SSebastien.Roy@Sun.COM case EPERM: 1653147Sxc151355 return (DLADM_STATUS_DENIED); 1663147Sxc151355 case EIO: 1673147Sxc151355 return (DLADM_STATUS_IOERR); 1685084Sjohnlev case EBUSY: 1695895Syz147064 return (DLADM_STATUS_LINKBUSY); 1705895Syz147064 case EAGAIN: 1715895Syz147064 return (DLADM_STATUS_TRYAGAIN); 1723147Sxc151355 default: 1733147Sxc151355 return (DLADM_STATUS_FAILED); 1743147Sxc151355 } 1753147Sxc151355 } 1763147Sxc151355 1775895Syz147064 #define LOCK_DB_PERMS S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH 1783147Sxc151355 1793147Sxc151355 static int 1803147Sxc151355 i_dladm_lock_db(const char *lock_file, short type) 1813147Sxc151355 { 1823147Sxc151355 int lock_fd; 1835895Syz147064 struct flock lock; 1843147Sxc151355 1853147Sxc151355 if ((lock_fd = open(lock_file, O_RDWR | O_CREAT | O_TRUNC, 1863147Sxc151355 LOCK_DB_PERMS)) < 0) 1873147Sxc151355 return (-1); 1883147Sxc151355 1893147Sxc151355 lock.l_type = type; 1903147Sxc151355 lock.l_whence = SEEK_SET; 1913147Sxc151355 lock.l_start = 0; 1923147Sxc151355 lock.l_len = 0; 1933147Sxc151355 1943147Sxc151355 if (fcntl(lock_fd, F_SETLKW, &lock) < 0) { 1953147Sxc151355 int err = errno; 1963147Sxc151355 1973147Sxc151355 (void) close(lock_fd); 1983147Sxc151355 (void) unlink(lock_file); 1993147Sxc151355 errno = err; 2003147Sxc151355 return (-1); 2013147Sxc151355 } 2023147Sxc151355 return (lock_fd); 2033147Sxc151355 } 2043147Sxc151355 2053147Sxc151355 static void 2063147Sxc151355 i_dladm_unlock_db(const char *lock_file, int fd) 2073147Sxc151355 { 2083147Sxc151355 struct flock lock; 2093147Sxc151355 2103147Sxc151355 if (fd < 0) 2113147Sxc151355 return; 2123147Sxc151355 2133147Sxc151355 lock.l_type = F_UNLCK; 2143147Sxc151355 lock.l_whence = SEEK_SET; 2153147Sxc151355 lock.l_start = 0; 2163147Sxc151355 lock.l_len = 0; 2173147Sxc151355 2183147Sxc151355 (void) fcntl(fd, F_SETLKW, &lock); 2193147Sxc151355 (void) close(fd); 2203147Sxc151355 (void) unlink(lock_file); 2213147Sxc151355 } 2223147Sxc151355 2235895Syz147064 /* 2245895Syz147064 * Given a link class, returns its class string. 2255895Syz147064 */ 2265895Syz147064 const char * 2275895Syz147064 dladm_class2str(datalink_class_t class, char *buf) 2285895Syz147064 { 2295895Syz147064 const char *s; 2305895Syz147064 2315895Syz147064 switch (class) { 2325895Syz147064 case DATALINK_CLASS_PHYS: 2335895Syz147064 s = "phys"; 2345895Syz147064 break; 2355895Syz147064 case DATALINK_CLASS_VLAN: 2365895Syz147064 s = "vlan"; 2375895Syz147064 break; 2385895Syz147064 case DATALINK_CLASS_AGGR: 2395895Syz147064 s = "aggr"; 2405895Syz147064 break; 2415895Syz147064 case DATALINK_CLASS_VNIC: 2425895Syz147064 s = "vnic"; 2435895Syz147064 break; 2445895Syz147064 default: 2455895Syz147064 s = "unknown"; 2465895Syz147064 break; 2475895Syz147064 } 2485895Syz147064 2495895Syz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", s); 2505895Syz147064 return (buf); 2515895Syz147064 } 2525895Syz147064 2535895Syz147064 /* 2545895Syz147064 * Given a physical link media type, returns its media type string. 2555895Syz147064 */ 2565895Syz147064 const char * 2575895Syz147064 dladm_media2str(uint32_t media, char *buf) 2585895Syz147064 { 2595895Syz147064 const char *s; 2605895Syz147064 2615895Syz147064 switch (media) { 2625895Syz147064 case DL_ETHER: 2635895Syz147064 s = "Ethernet"; 2645895Syz147064 break; 2655895Syz147064 case DL_WIFI: 2665895Syz147064 s = "WiFi"; 2675895Syz147064 break; 2685895Syz147064 case DL_IB: 2695895Syz147064 s = "Infiniband"; 2705895Syz147064 break; 2715895Syz147064 case DL_IPV4: 2725895Syz147064 s = "IPv4Tunnel"; 2735895Syz147064 break; 2745895Syz147064 case DL_IPV6: 2755895Syz147064 s = "IPv6Tunnel"; 2765895Syz147064 break; 2775895Syz147064 case DL_CSMACD: 2785895Syz147064 s = "CSMA/CD"; 2795895Syz147064 break; 2805895Syz147064 case DL_TPB: 2815895Syz147064 s = "TokenBus"; 2825895Syz147064 break; 2835895Syz147064 case DL_TPR: 2845895Syz147064 s = "TokenRing"; 2855895Syz147064 break; 2865895Syz147064 case DL_METRO: 2875895Syz147064 s = "MetroNet"; 2885895Syz147064 break; 2895895Syz147064 case DL_HDLC: 2905895Syz147064 s = "HDLC"; 2915895Syz147064 break; 2925895Syz147064 case DL_CHAR: 2935895Syz147064 s = "SyncCharacter"; 2945895Syz147064 break; 2955895Syz147064 case DL_CTCA: 2965895Syz147064 s = "CTCA"; 2975895Syz147064 break; 2985895Syz147064 case DL_FDDI: 2995895Syz147064 s = "FDDI"; 3005895Syz147064 break; 3015895Syz147064 case DL_FC: 3025895Syz147064 s = "FiberChannel"; 3035895Syz147064 break; 3045895Syz147064 case DL_ATM: 3055895Syz147064 s = "ATM"; 3065895Syz147064 break; 3075895Syz147064 case DL_IPATM: 3085895Syz147064 s = "ATM(ClassicIP)"; 3095895Syz147064 break; 3105895Syz147064 case DL_X25: 3115895Syz147064 s = "X.25"; 3125895Syz147064 break; 3135895Syz147064 case DL_IPX25: 3145895Syz147064 s = "X.25(ClassicIP)"; 3155895Syz147064 break; 3165895Syz147064 case DL_ISDN: 3175895Syz147064 s = "ISDN"; 3185895Syz147064 break; 3195895Syz147064 case DL_HIPPI: 3205895Syz147064 s = "HIPPI"; 3215895Syz147064 break; 3225895Syz147064 case DL_100VG: 3235895Syz147064 s = "100BaseVGEthernet"; 3245895Syz147064 break; 3255895Syz147064 case DL_100VGTPR: 3265895Syz147064 s = "100BaseVGTokenRing"; 3275895Syz147064 break; 3285895Syz147064 case DL_ETH_CSMA: 3295895Syz147064 s = "IEEE802.3"; 3305895Syz147064 break; 3315895Syz147064 case DL_100BT: 3325895Syz147064 s = "100BaseT"; 3335895Syz147064 break; 3345895Syz147064 case DL_FRAME: 3355895Syz147064 s = "FrameRelay"; 3365895Syz147064 break; 3375895Syz147064 case DL_MPFRAME: 3385895Syz147064 s = "MPFrameRelay"; 3395895Syz147064 break; 3405895Syz147064 case DL_ASYNC: 3415895Syz147064 s = "AsyncCharacter"; 3425895Syz147064 break; 3435895Syz147064 default: 3445895Syz147064 s = "--"; 3455895Syz147064 break; 3465895Syz147064 } 3475895Syz147064 3485895Syz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", s); 3495895Syz147064 return (buf); 3505895Syz147064 } 3515895Syz147064 3523147Sxc151355 dladm_status_t 3533147Sxc151355 i_dladm_rw_db(const char *db_file, mode_t db_perms, 3543147Sxc151355 dladm_status_t (*process_db)(void *, FILE *, FILE *), 3553147Sxc151355 void *arg, boolean_t writeop) 3563147Sxc151355 { 3573147Sxc151355 dladm_status_t status = DLADM_STATUS_OK; 3583147Sxc151355 FILE *fp, *nfp = NULL; 3593147Sxc151355 char lock[MAXPATHLEN]; 3603147Sxc151355 char file[MAXPATHLEN]; 3613147Sxc151355 char newfile[MAXPATHLEN]; 3623147Sxc151355 char *db_basename; 3633147Sxc151355 int nfd, lock_fd; 3643147Sxc151355 3653147Sxc151355 /* 3663147Sxc151355 * If we are called from a boot script such as net-physical, 3673147Sxc151355 * it's quite likely that the root fs is still not writable. 3683147Sxc151355 * For this case, it's ok for the lock creation to fail since 3693147Sxc151355 * no one else could be accessing our configuration file. 3703147Sxc151355 */ 3713147Sxc151355 db_basename = strrchr(db_file, '/'); 3723147Sxc151355 if (db_basename == NULL || db_basename[1] == '\0') 3733147Sxc151355 return (dladm_errno2status(EINVAL)); 3743147Sxc151355 db_basename++; 3753147Sxc151355 (void) snprintf(lock, MAXPATHLEN, "/tmp/%s.lock", db_basename); 3763147Sxc151355 if ((lock_fd = i_dladm_lock_db 3773147Sxc151355 (lock, (writeop ? F_WRLCK : F_RDLCK))) < 0 && errno != EROFS) 3783147Sxc151355 return (dladm_errno2status(errno)); 3793147Sxc151355 3803147Sxc151355 (void) snprintf(file, MAXPATHLEN, "%s/%s", dladm_rootdir, db_file); 3813147Sxc151355 if ((fp = fopen(file, (writeop ? "r+" : "r"))) == NULL) { 3823147Sxc151355 int err = errno; 3833147Sxc151355 3843147Sxc151355 i_dladm_unlock_db(lock, lock_fd); 3853147Sxc151355 if (err == ENOENT) 3863147Sxc151355 return (DLADM_STATUS_DBNOTFOUND); 3873147Sxc151355 3883147Sxc151355 return (dladm_errno2status(err)); 3893147Sxc151355 } 3903147Sxc151355 3913147Sxc151355 if (writeop) { 3923147Sxc151355 (void) snprintf(newfile, MAXPATHLEN, "%s/%s.new", 3933147Sxc151355 dladm_rootdir, db_file); 3943147Sxc151355 if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC, 3953147Sxc151355 db_perms)) < 0) { 3963147Sxc151355 (void) fclose(fp); 3973147Sxc151355 i_dladm_unlock_db(lock, lock_fd); 3983147Sxc151355 return (dladm_errno2status(errno)); 3993147Sxc151355 } 4003147Sxc151355 4013147Sxc151355 if ((nfp = fdopen(nfd, "w")) == NULL) { 4023147Sxc151355 (void) close(nfd); 4033147Sxc151355 (void) fclose(fp); 4043147Sxc151355 (void) unlink(newfile); 4053147Sxc151355 i_dladm_unlock_db(lock, lock_fd); 4063147Sxc151355 return (dladm_errno2status(errno)); 4073147Sxc151355 } 4083147Sxc151355 } 4093147Sxc151355 status = (*process_db)(arg, fp, nfp); 4103147Sxc151355 if (!writeop || status != DLADM_STATUS_OK) 4113147Sxc151355 goto done; 4123147Sxc151355 4133147Sxc151355 /* 4143147Sxc151355 * Configuration files need to be owned by the 'dladm' user. 4153147Sxc151355 * If we are invoked by root, the file ownership needs to be fixed. 4163147Sxc151355 */ 4173147Sxc151355 if (getuid() == 0 || geteuid() == 0) { 4186173Syz147064 if (fchown(nfd, UID_DLADM, GID_SYS) < 0) { 4193147Sxc151355 status = dladm_errno2status(errno); 4203147Sxc151355 goto done; 4213147Sxc151355 } 4223147Sxc151355 } 4233147Sxc151355 4243147Sxc151355 if (fflush(nfp) == EOF) { 4253147Sxc151355 status = dladm_errno2status(errno); 4263147Sxc151355 goto done; 4273147Sxc151355 } 4283147Sxc151355 (void) fclose(fp); 4293147Sxc151355 (void) fclose(nfp); 4303147Sxc151355 4313147Sxc151355 if (rename(newfile, file) < 0) { 4323147Sxc151355 (void) unlink(newfile); 4333147Sxc151355 i_dladm_unlock_db(lock, lock_fd); 4343147Sxc151355 return (dladm_errno2status(errno)); 4353147Sxc151355 } 4363147Sxc151355 4373147Sxc151355 i_dladm_unlock_db(lock, lock_fd); 4383147Sxc151355 return (DLADM_STATUS_OK); 4393147Sxc151355 4403147Sxc151355 done: 4413147Sxc151355 if (nfp != NULL) { 4423147Sxc151355 (void) fclose(nfp); 4433147Sxc151355 if (status != DLADM_STATUS_OK) 4443147Sxc151355 (void) unlink(newfile); 4453147Sxc151355 } 4463147Sxc151355 (void) fclose(fp); 4473147Sxc151355 i_dladm_unlock_db(lock, lock_fd); 4483147Sxc151355 return (status); 4493147Sxc151355 } 4503147Sxc151355 4513147Sxc151355 dladm_status_t 4523147Sxc151355 dladm_set_rootdir(const char *rootdir) 4533147Sxc151355 { 4543147Sxc151355 DIR *dp; 4553147Sxc151355 4563147Sxc151355 if (rootdir == NULL || *rootdir != '/' || 4573147Sxc151355 (dp = opendir(rootdir)) == NULL) 4583147Sxc151355 return (DLADM_STATUS_BADARG); 4593147Sxc151355 4603147Sxc151355 (void) strncpy(dladm_rootdir, rootdir, MAXPATHLEN); 4613147Sxc151355 (void) closedir(dp); 4623147Sxc151355 return (DLADM_STATUS_OK); 4633147Sxc151355 } 4645895Syz147064 4655895Syz147064 boolean_t 4665895Syz147064 dladm_valid_linkname(const char *link) 4675895Syz147064 { 4685895Syz147064 size_t len = strlen(link); 4695895Syz147064 const char *cp; 4705895Syz147064 4715895Syz147064 if (len + 1 >= MAXLINKNAMELEN) 4725895Syz147064 return (B_FALSE); 4735895Syz147064 4745895Syz147064 /* 4755895Syz147064 * The link name cannot start with a digit and must end with a digit. 4765895Syz147064 */ 4775895Syz147064 if ((isdigit(link[0]) != 0) || (isdigit(link[len - 1]) == 0)) 4785895Syz147064 return (B_FALSE); 4795895Syz147064 4805895Syz147064 /* 4815895Syz147064 * The legal characters in a link name are: 4825895Syz147064 * alphanumeric (a-z, A-Z, 0-9), and the underscore ('_'). 4835895Syz147064 */ 4845895Syz147064 for (cp = link; *cp != '\0'; cp++) { 4855895Syz147064 if ((isalnum(*cp) == 0) && (*cp != '_')) 4865895Syz147064 return (B_FALSE); 4875895Syz147064 } 4885895Syz147064 4895895Syz147064 return (B_TRUE); 4905895Syz147064 } 491