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