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
putalert(char * parent,char * name,FALERT * alertp)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 *
getalert(char * parent,char * name)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
delalert(char * parent,char * name)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
envlist(int fd,char ** list)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
printalert(FILE * fp,FALERT * alertp,int isfault)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