1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1997 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * Copyright (c) 2016 by Delphix. All rights reserved. 26 */ 27 28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 29 /* All Rights Reserved */ 30 31 /* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */ 32 33 #include "stdio.h" 34 #include "string.h" 35 #include "errno.h" 36 #include "limits.h" 37 #include "unistd.h" 38 39 #include "lp.h" 40 41 extern char **environ; 42 43 static void envlist(int, char **); 44 45 /* 46 * We recognize the following key phrases in the alert prototype 47 * file, and replace them with appropriate values. 48 */ 49 #define NALRT_KEYS 7 50 # define ALRT_ENV 0 51 # define ALRT_PWD 1 52 # define ALRT_ULIMIT 2 53 # define ALRT_UMASK 3 54 # define ALRT_INTERVAL 4 55 # define ALRT_CMD 5 56 # define ALRT_USER 6 57 58 static struct { 59 char *v; 60 short len; 61 } shell_keys[NALRT_KEYS] = { 62 #define ENTRY(X) X, sizeof(X)-1 63 ENTRY("-ENVIRONMENT-"), 64 ENTRY("-PWD-"), 65 ENTRY("-ULIMIT-"), 66 ENTRY("-UMASK-"), 67 ENTRY("-INTERVAL-"), 68 ENTRY("-CMD-"), 69 ENTRY("-USER-"), 70 }; 71 72 /* 73 * These are used to bracket the administrator's command, so that 74 * we can find it easily. We're out of luck if the administrator 75 * includes an identical phrase in their command. 76 */ 77 #define ALRT_CMDSTART "## YOUR COMMAND STARTS HERE -- DON'T TOUCH ABOVE!!" 78 #define ALRT_CMDEND "## YOUR COMMAND ENDS HERE -- DON'T TOUCH BELOW!!" 79 80 /** 81 ** putalert() - WRITE ALERT TO FILES 82 **/ 83 84 int 85 putalert(char *parent, char *name, FALERT *alertp) 86 { 87 char *path, 88 cur_dir[PATH_MAX + 1], 89 buf[BUFSIZ]; 90 91 int cur_umask; 92 93 int fdout, fdin; 94 95 96 if (!parent || !*parent || !name || !*name) { 97 errno = EINVAL; 98 return (-1); 99 } 100 101 if (!alertp->shcmd) { 102 errno = EINVAL; 103 return (-1); 104 } 105 106 if (STREQU(alertp->shcmd, NAME_NONE)) 107 return (delalert(parent, name)); 108 109 /* 110 * See if the form/printer/print-wheel exists. 111 */ 112 113 if (!(path = makepath(parent, name, (char *)0))) 114 return (-1); 115 116 if (Access(path, F_OK) == -1) { 117 if (errno == ENOENT) 118 errno = ENOTDIR; /* not quite, but what else? */ 119 Free (path); 120 return (-1); 121 } 122 Free (path); 123 124 /* 125 * First, the shell command file. 126 */ 127 128 if (!(path = makepath(parent, name, ALERTSHFILE, (char *)0))) 129 return (-1); 130 131 if ((fdout = open_locked(path, "w", MODE_NOEXEC)) < 0) { 132 Free (path); 133 return (-1); 134 } 135 Free (path); 136 137 /* 138 * We use a prototype file to build the shell command, 139 * so that the alerts are easily customized. The shell 140 * is expected to handle repeat alerts and failed alerts, 141 * because the Spooler doesn't. Also, the Spooler runs 142 * each alert with the UID and GID of the administrator 143 * who defined the alert. Otherwise, anything goes. 144 */ 145 146 if (!Lp_Bin) { 147 getpaths (); 148 if (!Lp_Bin) 149 return (-1); 150 } 151 if (!(path = makepath(Lp_Bin, ALERTPROTOFILE, (char *)0))) 152 return (-1); 153 154 if ((fdin = open_locked(path, "r", 0)) < 0) { 155 Free (path); 156 return (-1); 157 } 158 Free (path); 159 160 errno = 0; 161 while (fdgets(buf, BUFSIZ, fdin)) { 162 int key; 163 char *cp, 164 *dash; 165 166 cp = buf; 167 while ((dash = strchr(cp, '-'))) { 168 169 *dash = 0; 170 fdputs (cp, fdout); 171 *(cp = dash) = '-'; 172 173 for (key = 0; key < NALRT_KEYS; key++) 174 if (STRNEQU( 175 cp, 176 shell_keys[key].v, 177 shell_keys[key].len 178 )) { 179 register char *newline = 180 (cp != buf)? "\n" : ""; 181 182 cp += shell_keys[key].len; 183 184 switch (key) { 185 186 case ALRT_ENV: 187 fdprintf(fdout, newline); 188 envlist(fdout, environ); 189 break; 190 191 case ALRT_PWD: 192 getcwd (cur_dir, PATH_MAX); 193 fdprintf (fdout, "%s", cur_dir); 194 break; 195 196 case ALRT_ULIMIT: 197 fdprintf (fdout, "%ld", ulimit(1, (long)0)); 198 break; 199 200 case ALRT_UMASK: 201 umask (cur_umask = umask(0)); 202 fdprintf (fdout, "%03o", cur_umask); 203 break; 204 205 case ALRT_INTERVAL: 206 fdprintf(fdout, "%ld", (long)alertp->W); 207 break; 208 209 case ALRT_CMD: 210 fdprintf(fdout, newline); 211 fdprintf(fdout, "%s\n", ALRT_CMDSTART); 212 fdprintf(fdout, "%s\n", alertp->shcmd); 213 fdprintf(fdout, "%s\n", ALRT_CMDEND); 214 break; 215 216 case ALRT_USER: 217 fdprintf(fdout, "%s", getname()); 218 break; 219 220 } 221 222 break; 223 } 224 if (key >= NALRT_KEYS) 225 fdputc(*cp++, fdout); 226 227 } 228 fdputs(cp, fdout); 229 230 } 231 if (errno != 0) { 232 int save_errno = errno; 233 234 close(fdin); 235 close(fdout); 236 errno = save_errno; 237 return (-1); 238 } 239 close(fdin); 240 close(fdout); 241 242 /* 243 * Next, the variables file. 244 */ 245 246 if (!(path = makepath(parent, name, ALERTVARSFILE, (char *)0))) 247 return (-1); 248 249 if ((fdout = open_locked(path, "w", MODE_NOREAD)) < 0) { 250 Free (path); 251 return (-1); 252 } 253 Free (path); 254 255 fdprintf(fdout, "%d\n", alertp->Q > 0? alertp->Q : 1); 256 fdprintf(fdout, "%d\n", alertp->W >= 0? alertp->W : 0); 257 258 close(fdout); 259 260 return (0); 261 } 262 263 /** 264 ** getalert() - EXTRACT ALERT FROM FILES 265 **/ 266 267 FALERT * 268 getalert(char *parent, char *name) 269 { 270 int fd; 271 char *tmp; 272 static FALERT alert; 273 register char *path; 274 char buf[BUFSIZ]; 275 int len; 276 277 if (!parent || !*parent || !name || !*name) { 278 errno = EINVAL; 279 return (0); 280 } 281 282 /* 283 * See if the form/printer/print-wheel exists. 284 */ 285 286 if (!(path = makepath(parent, name, (char *)0))) 287 return (0); 288 289 if (Access(path, F_OK) == -1) { 290 if (errno == ENOENT) 291 errno = ENOTDIR; /* not quite, but what else? */ 292 Free (path); 293 return (0); 294 } 295 Free (path); 296 297 /* 298 * First, the shell command file. 299 */ 300 301 if (!(path = makepath(parent, name, ALERTSHFILE, (char *)0))) 302 return (0); 303 304 if ((fd = open_locked(path, "r", 0)) < 0) { 305 Free (path); 306 return (0); 307 } 308 Free (path); 309 310 /* 311 * Skip over environment setting stuff, while loop, etc., 312 * to find the beginning of the command. 313 */ 314 errno = 0; 315 while ((tmp = fdgets(buf, BUFSIZ, fd)) && 316 !STRNEQU(buf, ALRT_CMDSTART, sizeof(ALRT_CMDSTART)-1)) 317 ; 318 if ((tmp == NULL) || (errno != 0)) { 319 int save_errno = errno; 320 321 close(fd); 322 errno = save_errno; 323 return (0); 324 } 325 326 alert.shcmd = sop_up_rest(fd, ALRT_CMDEND); 327 328 close(fd); 329 330 if (!alert.shcmd) 331 return (0); 332 333 /* 334 * Drop terminating newline. 335 */ 336 if (alert.shcmd[(len = strlen(alert.shcmd)) - 1] == '\n') 337 alert.shcmd[len - 1] = 0; 338 339 340 /* 341 * Next, the variables file. 342 */ 343 344 if (!(path = makepath(parent, name, ALERTVARSFILE, (char *)0))) 345 return (0); 346 347 if ((fd = open_locked(path, "r", 0)) < 0) { 348 Free (path); 349 return (0); 350 } 351 Free (path); 352 353 errno = 0; 354 (void)fdgets (buf, BUFSIZ, fd); 355 if (errno != 0) { 356 int save_errno = errno; 357 358 close(fd); 359 errno = save_errno; 360 return (0); 361 } 362 alert.Q = atoi(buf); 363 364 (void)fdgets (buf, BUFSIZ, fd); 365 if (errno != 0) { 366 int save_errno = errno; 367 368 close(fd); 369 errno = save_errno; 370 return (0); 371 } 372 alert.W = atoi(buf); 373 374 close(fd); 375 376 return (&alert); 377 } 378 379 /** 380 ** delalert() - DELETE ALERT FILES 381 **/ 382 383 int 384 delalert(char *parent, char *name) 385 { 386 char *path; 387 388 389 if (!parent || !*parent || !name || !*name) { 390 errno = EINVAL; 391 return (-1); 392 } 393 394 /* 395 * See if the form/printer/print-wheel exists. 396 */ 397 398 if (!(path = makepath(parent, name, (char *)0))) 399 return (-1); 400 401 if (Access(path, F_OK) == -1) { 402 if (errno == ENOENT) 403 errno = ENOTDIR; /* not quite, but what else? */ 404 Free (path); 405 return (-1); 406 } 407 Free (path); 408 409 /* 410 * Remove the two files. 411 */ 412 413 if (!(path = makepath(parent, name, ALERTSHFILE, (char *)0))) 414 return (-1); 415 if (rmfile(path) == -1) { 416 Free (path); 417 return (-1); 418 } 419 Free (path); 420 421 if (!(path = makepath(parent, name, ALERTVARSFILE, (char *)0))) 422 return (-1); 423 if (rmfile(path) == -1) { 424 Free (path); 425 return (-1); 426 } 427 Free (path); 428 429 return (0); 430 } 431 432 /** 433 ** envlist() - PRINT OUT ENVIRONMENT LIST SAFELY 434 **/ 435 436 static void 437 envlist(int fd, char **list) 438 { 439 register char *env, 440 *value; 441 442 if (!list || !*list) 443 return; 444 445 while ((env = *list++)) { 446 if (!(value = strchr(env, '='))) 447 continue; 448 *value++ = 0; 449 if (!strchr(value, '\'')) 450 fdprintf(fd, (char *)gettext("export %s; %s='%s'\n"), 451 env, env, value); 452 *--value = '='; 453 } 454 } 455 456 /* 457 * printalert() - PRINT ALERT DESCRIPTION 458 * 459 * This is not used in the scheduler, so we don't need to switch to using 460 * file descriptors for scalability. 461 */ 462 463 void 464 printalert(FILE *fp, FALERT *alertp, int isfault) 465 { 466 if (!alertp->shcmd) { 467 if (isfault) 468 (void)fprintf (fp, (char *)gettext("On fault: no alert\n")); 469 else 470 (void)fprintf (fp, (char *)gettext("No alert\n")); 471 472 } else { 473 register char *copy = Strdup(alertp->shcmd), 474 *cp; 475 476 if (isfault) 477 (void)fprintf (fp, (char *)gettext("On fault: ")); 478 else 479 if (alertp->Q > 1) 480 (void)fprintf ( 481 fp, 482 (char *)gettext("When %d are queued: "), 483 alertp->Q 484 ); 485 else 486 (void)fprintf (fp, (char *)gettext("Upon any being queued: ")); 487 488 if (copy && (cp = strchr(copy, ' '))) 489 while (*cp == ' ') 490 *cp++ = 0; 491 492 if ( 493 copy 494 && syn_name(cp) 495 && ( 496 STREQU(copy, NAME_WRITE) 497 || STREQU(copy, NAME_MAIL) 498 ) 499 ) 500 (void)fprintf (fp, "%s to %s ", copy, cp); 501 else 502 (void)fprintf (fp, (char *)gettext("alert with \"%s\" "), alertp->shcmd); 503 504 if (alertp->W > 0) 505 (void)fprintf (fp, (char *)gettext("every %d minutes\n"), alertp->W); 506 else 507 (void)fprintf (fp, (char *)gettext("once\n")); 508 509 Free (copy); 510 } 511 return; 512 } 513