1*d71dbb73Sjbeck /* 2*d71dbb73Sjbeck * CDDL HEADER START 3*d71dbb73Sjbeck * 4*d71dbb73Sjbeck * The contents of this file are subject to the terms of the 5*d71dbb73Sjbeck * Common Development and Distribution License (the "License"). 6*d71dbb73Sjbeck * You may not use this file except in compliance with the License. 7*d71dbb73Sjbeck * 8*d71dbb73Sjbeck * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*d71dbb73Sjbeck * or http://www.opensolaris.org/os/licensing. 10*d71dbb73Sjbeck * See the License for the specific language governing permissions 11*d71dbb73Sjbeck * and limitations under the License. 12*d71dbb73Sjbeck * 13*d71dbb73Sjbeck * When distributing Covered Code, include this CDDL HEADER in each 14*d71dbb73Sjbeck * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*d71dbb73Sjbeck * If applicable, add the following below this CDDL HEADER, with the 16*d71dbb73Sjbeck * fields enclosed by brackets "[]" replaced with your own identifying 17*d71dbb73Sjbeck * information: Portions Copyright [yyyy] [name of copyright owner] 18*d71dbb73Sjbeck * 19*d71dbb73Sjbeck * CDDL HEADER END 20*d71dbb73Sjbeck */ 21*d71dbb73Sjbeck 22*d71dbb73Sjbeck /* 23*d71dbb73Sjbeck * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24*d71dbb73Sjbeck * Use is subject to license terms. 25*d71dbb73Sjbeck */ 26*d71dbb73Sjbeck 27*d71dbb73Sjbeck #pragma ident "%Z%%M% %I% %E% SMI" 28*d71dbb73Sjbeck 29*d71dbb73Sjbeck /* 30*d71dbb73Sjbeck * util.c contains a set of miscellaneous utility functions which: 31*d71dbb73Sjbeck * - syslog(LOG_DEBUG, ...) if debugging is enabled 32*d71dbb73Sjbeck * - check for an IP interface being marked running 33*d71dbb73Sjbeck * - look up all flags for an IP interface 34*d71dbb73Sjbeck * - start a child process 35*d71dbb73Sjbeck * - schedule a timer 36*d71dbb73Sjbeck * - check to see if a user is logged in to a graphical console 37*d71dbb73Sjbeck * - look up the zone name 38*d71dbb73Sjbeck */ 39*d71dbb73Sjbeck 40*d71dbb73Sjbeck #include <stdarg.h> 41*d71dbb73Sjbeck #include <stdio.h> 42*d71dbb73Sjbeck #include <stdlib.h> 43*d71dbb73Sjbeck #include <unistd.h> 44*d71dbb73Sjbeck #include <pthread.h> 45*d71dbb73Sjbeck #include <string.h> 46*d71dbb73Sjbeck #include <strings.h> 47*d71dbb73Sjbeck #include <stropts.h> 48*d71dbb73Sjbeck #include <syslog.h> 49*d71dbb73Sjbeck #include <sys/types.h> 50*d71dbb73Sjbeck #include <sys/socket.h> 51*d71dbb73Sjbeck #include <sys/sockio.h> 52*d71dbb73Sjbeck #include <net/if.h> 53*d71dbb73Sjbeck #include <spawn.h> 54*d71dbb73Sjbeck #include <wait.h> 55*d71dbb73Sjbeck #include <inetcfg.h> 56*d71dbb73Sjbeck #include <utmpx.h> 57*d71dbb73Sjbeck #include <pwd.h> 58*d71dbb73Sjbeck #include <limits.h> 59*d71dbb73Sjbeck #include <errno.h> 60*d71dbb73Sjbeck #include <zone.h> 61*d71dbb73Sjbeck 62*d71dbb73Sjbeck #include "defines.h" 63*d71dbb73Sjbeck #include "structures.h" 64*d71dbb73Sjbeck #include "functions.h" 65*d71dbb73Sjbeck #include "variables.h" 66*d71dbb73Sjbeck 67*d71dbb73Sjbeck extern char **environ; 68*d71dbb73Sjbeck boolean_t debug = B_FALSE; 69*d71dbb73Sjbeck 70*d71dbb73Sjbeck void 71*d71dbb73Sjbeck dprintf(const char *fmt, ...) 72*d71dbb73Sjbeck { 73*d71dbb73Sjbeck va_list ap; 74*d71dbb73Sjbeck char vbuf[1024]; 75*d71dbb73Sjbeck 76*d71dbb73Sjbeck va_start(ap, fmt); 77*d71dbb73Sjbeck if (debug) { 78*d71dbb73Sjbeck (void) vsnprintf(vbuf, sizeof (vbuf), fmt, ap); 79*d71dbb73Sjbeck syslog(LOG_DEBUG, "%d: %s", pthread_self(), vbuf); 80*d71dbb73Sjbeck } 81*d71dbb73Sjbeck va_end(ap); 82*d71dbb73Sjbeck } 83*d71dbb73Sjbeck 84*d71dbb73Sjbeck boolean_t 85*d71dbb73Sjbeck is_plugged_in(struct interface *i) 86*d71dbb73Sjbeck { 87*d71dbb73Sjbeck if (i->if_type == IF_WIRELESS) 88*d71dbb73Sjbeck return (B_TRUE); 89*d71dbb73Sjbeck 90*d71dbb73Sjbeck return ((get_ifflags(i->if_name, i->if_family) & IFF_RUNNING) != 0); 91*d71dbb73Sjbeck } 92*d71dbb73Sjbeck 93*d71dbb73Sjbeck uint64_t 94*d71dbb73Sjbeck get_ifflags(const char *name, sa_family_t family) 95*d71dbb73Sjbeck { 96*d71dbb73Sjbeck icfg_if_t intf; 97*d71dbb73Sjbeck icfg_handle_t h; 98*d71dbb73Sjbeck uint64_t flags = 0; 99*d71dbb73Sjbeck 100*d71dbb73Sjbeck (void) strlcpy(intf.if_name, name, sizeof (intf.if_name)); 101*d71dbb73Sjbeck intf.if_protocol = family; 102*d71dbb73Sjbeck 103*d71dbb73Sjbeck if (icfg_open(&h, &intf) != ICFG_SUCCESS) 104*d71dbb73Sjbeck return (0); 105*d71dbb73Sjbeck 106*d71dbb73Sjbeck if (icfg_get_flags(h, &flags) != ICFG_SUCCESS) { 107*d71dbb73Sjbeck /* 108*d71dbb73Sjbeck * Interfaces can be ripped out from underneath us (for example 109*d71dbb73Sjbeck * by DHCP). We don't want to spam the console for those. 110*d71dbb73Sjbeck */ 111*d71dbb73Sjbeck if (errno == ENOENT) 112*d71dbb73Sjbeck dprintf("get_ifflags: icfg_get_flags failed for '%s'", 113*d71dbb73Sjbeck name); 114*d71dbb73Sjbeck else 115*d71dbb73Sjbeck syslog(LOG_ERR, "get_ifflags: icfg_get_flags %s af " 116*d71dbb73Sjbeck "%d: %m", name, family); 117*d71dbb73Sjbeck /* just to be sure... */ 118*d71dbb73Sjbeck flags = 0; 119*d71dbb73Sjbeck } 120*d71dbb73Sjbeck icfg_close(h); 121*d71dbb73Sjbeck 122*d71dbb73Sjbeck return (flags); 123*d71dbb73Sjbeck } 124*d71dbb73Sjbeck 125*d71dbb73Sjbeck /* 126*d71dbb73Sjbeck * 127*d71dbb73Sjbeck * This starts a child process determined by command. If command contains a 128*d71dbb73Sjbeck * slash then it is assumed to be a full path; otherwise the path is searched 129*d71dbb73Sjbeck * for an executable file with the name command. Command is also used as 130*d71dbb73Sjbeck * argv[0] of the new process. The rest of the arguments of the function 131*d71dbb73Sjbeck * up to the first NULL make up pointers to arguments of the new process. 132*d71dbb73Sjbeck * 133*d71dbb73Sjbeck * This function returns child exit status on success and -1 on failure. 134*d71dbb73Sjbeck * 135*d71dbb73Sjbeck * NOTE: original_sigmask must be set before this function is called. 136*d71dbb73Sjbeck */ 137*d71dbb73Sjbeck int 138*d71dbb73Sjbeck start_childv(const char *command, char const * const *argv) 139*d71dbb73Sjbeck { 140*d71dbb73Sjbeck posix_spawnattr_t attr; 141*d71dbb73Sjbeck sigset_t fullset; 142*d71dbb73Sjbeck int i, rc, status, n; 143*d71dbb73Sjbeck pid_t pid; 144*d71dbb73Sjbeck char vbuf[1024]; 145*d71dbb73Sjbeck 146*d71dbb73Sjbeck vbuf[0] = 0; 147*d71dbb73Sjbeck n = sizeof (vbuf); 148*d71dbb73Sjbeck for (i = 1; argv[i] != NULL && n > 2; i++) { 149*d71dbb73Sjbeck n -= strlcat(vbuf, " ", n); 150*d71dbb73Sjbeck n -= strlcat(vbuf, argv[i], n); 151*d71dbb73Sjbeck } 152*d71dbb73Sjbeck if (argv[i] != NULL || n < 0) 153*d71dbb73Sjbeck syslog(LOG_ERR, "start_childv can't log full arg vector"); 154*d71dbb73Sjbeck 155*d71dbb73Sjbeck if ((rc = posix_spawnattr_init(&attr)) != 0) { 156*d71dbb73Sjbeck dprintf("posix_spawnattr_init %d %s\n", rc, strerror(rc)); 157*d71dbb73Sjbeck return (-1); 158*d71dbb73Sjbeck } 159*d71dbb73Sjbeck (void) sigfillset(&fullset); 160*d71dbb73Sjbeck if ((rc = posix_spawnattr_setsigdefault(&attr, &fullset)) != 0) { 161*d71dbb73Sjbeck dprintf("setsigdefault %d %s\n", rc, strerror(rc)); 162*d71dbb73Sjbeck return (-1); 163*d71dbb73Sjbeck } 164*d71dbb73Sjbeck if ((rc = posix_spawnattr_setsigmask(&attr, &original_sigmask)) != 0) { 165*d71dbb73Sjbeck dprintf("setsigmask %d %s\n", rc, strerror(rc)); 166*d71dbb73Sjbeck return (-1); 167*d71dbb73Sjbeck } 168*d71dbb73Sjbeck if ((rc = posix_spawnattr_setflags(&attr, 169*d71dbb73Sjbeck POSIX_SPAWN_SETSIGDEF|POSIX_SPAWN_SETSIGMASK)) != 0) { 170*d71dbb73Sjbeck dprintf("setflags %d %s\n", rc, strerror(rc)); 171*d71dbb73Sjbeck return (-1); 172*d71dbb73Sjbeck } 173*d71dbb73Sjbeck 174*d71dbb73Sjbeck if ((rc = posix_spawnp(&pid, command, NULL, &attr, (char * const *)argv, 175*d71dbb73Sjbeck environ)) > 0) { 176*d71dbb73Sjbeck dprintf("posix_spawnp failed errno %d", rc); 177*d71dbb73Sjbeck return (-1); 178*d71dbb73Sjbeck } 179*d71dbb73Sjbeck 180*d71dbb73Sjbeck if ((rc = posix_spawnattr_destroy(&attr)) != 0) { 181*d71dbb73Sjbeck dprintf("posix_spawn_attr_destroy %d %s\n", rc, strerror(rc)); 182*d71dbb73Sjbeck return (-1); 183*d71dbb73Sjbeck } 184*d71dbb73Sjbeck 185*d71dbb73Sjbeck (void) waitpid(pid, &status, 0); 186*d71dbb73Sjbeck if (WIFSIGNALED(status) || WIFSTOPPED(status)) { 187*d71dbb73Sjbeck i = WIFSIGNALED(status) ? WTERMSIG(status) : WSTOPSIG(status); 188*d71dbb73Sjbeck syslog(LOG_ERR, "'%s%s' %s with signal %d (%s)", command, vbuf, 189*d71dbb73Sjbeck (WIFSIGNALED(status) ? "terminated" : "stopped"), i, 190*d71dbb73Sjbeck strsignal(i)); 191*d71dbb73Sjbeck return (-2); 192*d71dbb73Sjbeck } else { 193*d71dbb73Sjbeck syslog(LOG_INFO, "'%s%s' completed normally: %d", command, vbuf, 194*d71dbb73Sjbeck WEXITSTATUS(status)); 195*d71dbb73Sjbeck return (WEXITSTATUS(status)); 196*d71dbb73Sjbeck } 197*d71dbb73Sjbeck } 198*d71dbb73Sjbeck 199*d71dbb73Sjbeck int 200*d71dbb73Sjbeck start_child(const char *command, ...) 201*d71dbb73Sjbeck { 202*d71dbb73Sjbeck const char **argv = NULL; 203*d71dbb73Sjbeck int argv_len = 0; 204*d71dbb73Sjbeck va_list ap; 205*d71dbb73Sjbeck int i = 1, rc; 206*d71dbb73Sjbeck 207*d71dbb73Sjbeck va_start(ap, command); 208*d71dbb73Sjbeck do { 209*d71dbb73Sjbeck if (i >= argv_len) { 210*d71dbb73Sjbeck void *p; 211*d71dbb73Sjbeck 212*d71dbb73Sjbeck argv_len = argv_len != 0 ? argv_len * 2 : 4; 213*d71dbb73Sjbeck p = realloc(argv, sizeof (*argv)*argv_len); 214*d71dbb73Sjbeck if (p != NULL) { 215*d71dbb73Sjbeck argv = p; 216*d71dbb73Sjbeck } else { 217*d71dbb73Sjbeck syslog(LOG_ERR, "Out of memory in start_child"); 218*d71dbb73Sjbeck free(argv); 219*d71dbb73Sjbeck return (-1); 220*d71dbb73Sjbeck } 221*d71dbb73Sjbeck } 222*d71dbb73Sjbeck 223*d71dbb73Sjbeck argv[i] = va_arg(ap, const char *); 224*d71dbb73Sjbeck } while (argv[i++] != NULL); 225*d71dbb73Sjbeck va_end(ap); 226*d71dbb73Sjbeck argv[0] = command; 227*d71dbb73Sjbeck 228*d71dbb73Sjbeck rc = start_childv(command, argv); 229*d71dbb73Sjbeck free(argv); 230*d71dbb73Sjbeck 231*d71dbb73Sjbeck return (rc); 232*d71dbb73Sjbeck } 233*d71dbb73Sjbeck 234*d71dbb73Sjbeck uint32_t timer_expire = TIMER_INFINITY; 235*d71dbb73Sjbeck 236*d71dbb73Sjbeck /* 237*d71dbb73Sjbeck * Schedules a SIGALRM in delay seconds, unless one is already 238*d71dbb73Sjbeck * scheduled sooner. If one is already scheduled later than 239*d71dbb73Sjbeck * delay seconds from now, that one will be replaced. 240*d71dbb73Sjbeck */ 241*d71dbb73Sjbeck void 242*d71dbb73Sjbeck start_timer(uint32_t now, uint32_t delay) 243*d71dbb73Sjbeck { 244*d71dbb73Sjbeck if (now + delay > timer_expire) 245*d71dbb73Sjbeck return; 246*d71dbb73Sjbeck 247*d71dbb73Sjbeck timer_expire = now + delay; 248*d71dbb73Sjbeck (void) alarm(delay); 249*d71dbb73Sjbeck } 250*d71dbb73Sjbeck 251*d71dbb73Sjbeck boolean_t 252*d71dbb73Sjbeck valid_graphical_user(boolean_t query) 253*d71dbb73Sjbeck { 254*d71dbb73Sjbeck struct utmpx *utp; 255*d71dbb73Sjbeck char *user = NULL; 256*d71dbb73Sjbeck const char HOMESTR[] = "HOME="; 257*d71dbb73Sjbeck char buf[1024]; /* == sysconf(_SC_GETPW_R_SIZE_MAX) == NSS_BUFSIZ */ 258*d71dbb73Sjbeck static char home_dir[PATH_MAX + sizeof (HOMESTR)]; 259*d71dbb73Sjbeck struct passwd passwd; 260*d71dbb73Sjbeck struct passwd *pw; 261*d71dbb73Sjbeck boolean_t popup_ok; 262*d71dbb73Sjbeck 263*d71dbb73Sjbeck /* 264*d71dbb73Sjbeck * Check to see if our SMF property says popups are OK. 265*d71dbb73Sjbeck */ 266*d71dbb73Sjbeck if ((lookup_boolean_property(OUR_PG, query ? "popup_query" : 267*d71dbb73Sjbeck "popup_info", &popup_ok) == 0) && !popup_ok) 268*d71dbb73Sjbeck return (B_FALSE); 269*d71dbb73Sjbeck 270*d71dbb73Sjbeck /* 271*d71dbb73Sjbeck * Look for someone logged into the console from host ":0" (i.e., 272*d71dbb73Sjbeck * the X display. Down the road, we should generalize this so 273*d71dbb73Sjbeck * ":0" is not hard-coded. 274*d71dbb73Sjbeck */ 275*d71dbb73Sjbeck setutxent(); 276*d71dbb73Sjbeck while ((utp = getutxent()) != NULL) { 277*d71dbb73Sjbeck if ((utp->ut_type == USER_PROCESS) && 278*d71dbb73Sjbeck (strcmp(utp->ut_line, "console") == 0) && 279*d71dbb73Sjbeck (strcmp(utp->ut_host, ":0") == 0)) { 280*d71dbb73Sjbeck user = strdup(utp->ut_user); 281*d71dbb73Sjbeck break; 282*d71dbb73Sjbeck } 283*d71dbb73Sjbeck } 284*d71dbb73Sjbeck endutxent(); 285*d71dbb73Sjbeck dprintf("utmpx: done %s", user != NULL ? user : ""); 286*d71dbb73Sjbeck 287*d71dbb73Sjbeck if (user == NULL) 288*d71dbb73Sjbeck return (B_FALSE); 289*d71dbb73Sjbeck 290*d71dbb73Sjbeck pw = getpwnam_r(user, &passwd, buf, sizeof (buf)); 291*d71dbb73Sjbeck if (pw == NULL) { 292*d71dbb73Sjbeck syslog(LOG_ERR, "couldn't get user %s: %m", user); 293*d71dbb73Sjbeck free(user); 294*d71dbb73Sjbeck return (B_FALSE); 295*d71dbb73Sjbeck } 296*d71dbb73Sjbeck free(user); 297*d71dbb73Sjbeck 298*d71dbb73Sjbeck /* 299*d71dbb73Sjbeck * We shouldn't be dumping this into our environment or changing 300*d71dbb73Sjbeck * our uid/gid but instead starting up the zenity processes with 301*d71dbb73Sjbeck * this display as this user. RFE to change this. 302*d71dbb73Sjbeck */ 303*d71dbb73Sjbeck (void) putenv("DISPLAY=:0.0"); 304*d71dbb73Sjbeck 305*d71dbb73Sjbeck (void) strlcpy(home_dir, HOMESTR, sizeof (home_dir)); 306*d71dbb73Sjbeck (void) strlcat(home_dir, pw->pw_dir, sizeof (home_dir)); 307*d71dbb73Sjbeck (void) putenv(home_dir); 308*d71dbb73Sjbeck 309*d71dbb73Sjbeck return (pw != NULL); 310*d71dbb73Sjbeck } 311*d71dbb73Sjbeck 312*d71dbb73Sjbeck void 313*d71dbb73Sjbeck lookup_zonename(char *zonename, size_t zonesize) 314*d71dbb73Sjbeck { 315*d71dbb73Sjbeck zoneid_t zoneid = getzoneid(); 316*d71dbb73Sjbeck 317*d71dbb73Sjbeck if (getzonenamebyid(zoneid, zonename, zonesize) >= 0) 318*d71dbb73Sjbeck return; 319*d71dbb73Sjbeck syslog(LOG_ERR, "could not determine zone name"); 320*d71dbb73Sjbeck (void) strlcpy(zonename, GLOBAL_ZONENAME, zonesize); 321*d71dbb73Sjbeck } 322