]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/process.c
Normalize the permission checking code, and check permissions in more places.
[thirdparty/cups.git] / scheduler / process.c
1 /*
2 * "$Id$"
3 *
4 * Process management routines for the CUPS scheduler.
5 *
6 * Copyright 2007-2011 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
8 *
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
14 *
15 * Contents:
16 *
17 * cupsdCheckProgram() - Check the permissions of the given program and its
18 * containing directory.
19 * cupsdCreateProfile() - Create an execution profile for a subprocess.
20 * cupsdDestroyProfile() - Delete an execution profile.
21 * cupsdEndProcess() - End a process.
22 * cupsdFinishProcess() - Finish a process and get its name.
23 * cupsdStartProcess() - Start a process.
24 * compare_procs() - Compare two processes.
25 * cupsd_requote() - Make a regular-expression version of a string.
26 */
27
28 /*
29 * Include necessary headers...
30 */
31
32 #include "cupsd.h"
33 #include <grp.h>
34 #ifdef __APPLE__
35 # include <libgen.h>
36 #endif /* __APPLE__ */
37
38
39 /*
40 * Process structure...
41 */
42
43 typedef struct
44 {
45 int pid, /* Process ID */
46 job_id; /* Job associated with process */
47 char name[1]; /* Name of process */
48 } cupsd_proc_t;
49
50
51 /*
52 * Local globals...
53 */
54
55 static cups_array_t *process_array = NULL;
56
57
58 /*
59 * Local functions...
60 */
61
62 static int compare_procs(cupsd_proc_t *a, cupsd_proc_t *b);
63 #ifdef HAVE_SANDBOX_H
64 static char *cupsd_requote(char *dst, const char *src, size_t dstsize);
65 #endif /* HAVE_SANDBOX_H */
66
67
68 /*
69 * 'cupsdCheckProgram()' - Check the permissions of the given program and its
70 * containing directory.
71 */
72
73 int /* O - 1 if OK, 0 if not OK */
74 cupsdCheckProgram(
75 const char *filename, /* I - Filename to check */
76 cupsd_printer_t *p) /* I - Printer, if any */
77 {
78 struct stat fileinfo; /* File information */
79 char temp[1024], /* Parent directory filename */
80 *ptr; /* Pointer into parent directory */
81
82
83 /*
84 * Does the program even exist and is it accessible?
85 */
86
87 if (stat(filename, &fileinfo))
88 {
89 /*
90 * Nope...
91 */
92
93 if (p)
94 {
95 snprintf(p->state_message, sizeof(p->state_message),
96 "Printer driver \"%s\" not available: %s", filename,
97 strerror(errno));
98 cupsdLogMessage(CUPSD_LOG_ERROR, "%s: %s", p->name, p->state_message);
99
100 if (cupsdSetPrinterReasons(p, "+cups-missing-filter-warning"))
101 cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, p, NULL,
102 "Printer driver \"%s\" not available.", filename);
103 }
104 else
105 cupsdLogMessage(CUPSD_LOG_ERROR, "Program \"%s\" not available: %s",
106 filename, strerror(errno));
107
108 return (0);
109 }
110
111 /*
112 * Are we running as root?
113 */
114
115 if (RunUser)
116 {
117 /*
118 * Nope, so anything goes...
119 */
120
121 return (1);
122 }
123
124 /*
125 * Verify permission of the program itself:
126 *
127 * 1. Must be owned by root
128 * 2. Must not be writable by group unless group is root/wheel/admin
129 * 3. Must not be setuid
130 * 4. Must not be writable by others
131 */
132
133 if (fileinfo.st_uid || /* 1. Must be owned by root */
134 #ifdef __APPLE__
135 ((fileinfo.st_mode & S_IWGRP) && fileinfo.st_gid &&
136 fileinfo.st_gid != 80) || /* 2. Must not be writable by group */
137 #else
138 ((fileinfo.st_mode & S_IWGRP) && fileinfo.st_gid) ||
139 /* 2. Must not be writable by group */
140 #endif /* __APPLE__ */
141 (fileinfo.st_mode & S_ISUID) || /* 3. Must not be setuid */
142 (fileinfo.st_mode & S_IWOTH)) /* 4. Must not be writable by others */
143 {
144 if (p)
145 {
146 snprintf(p->state_message, sizeof(p->state_message),
147 "Printer driver \"%s\" has insecure permissions "
148 "(0%o/uid=%d/gid=%d).", filename, fileinfo.st_mode,
149 (int)fileinfo.st_uid, (int)fileinfo.st_gid);
150
151 cupsdLogMessage(CUPSD_LOG_ERROR, "%s: %s", p->name, p->state_message);
152
153 if (cupsdSetPrinterReasons(p, "+cups-insecure-filter-warning"))
154 cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, p, NULL, "%s",
155 p->state_message);
156 }
157 else
158 cupsdLogMessage(CUPSD_LOG_ERROR,
159 "Program \"%s\" has insecure permissions "
160 "(0%o/uid=%d/gid=%d).", filename, fileinfo.st_mode,
161 (int)fileinfo.st_uid, (int)fileinfo.st_gid);
162
163 errno = EPERM;
164
165 return (0);
166 }
167
168 cupsdLogMessage(CUPSD_LOG_DEBUG2,
169 "%s%s \"%s\" permissions OK "
170 "(0%o/uid=%d/gid=%d).", p ? p->name : "",
171 p ? ": Printer driver" : "Program", filename,
172 fileinfo.st_mode, (int)fileinfo.st_uid,
173 (int)fileinfo.st_gid);
174
175 /*
176 * Now check the containing directory...
177 */
178
179 strlcpy(temp, filename, sizeof(temp));
180 if ((ptr = strrchr(temp, '/')) != NULL)
181 {
182 if (ptr == temp)
183 ptr[1] = '\0';
184 else
185 *ptr = '\0';
186 }
187
188 if (stat(temp, &fileinfo))
189 {
190 /*
191 * Doesn't exist...
192 */
193
194 if (p)
195 {
196 snprintf(p->state_message, sizeof(p->state_message),
197 "Printer driver directory \"%s\" not available: %s", temp,
198 strerror(errno));
199 cupsdLogMessage(CUPSD_LOG_ERROR, "%s: %s", p->name, p->state_message);
200
201 if (cupsdSetPrinterReasons(p, "+cups-missing-filter-warning"))
202 cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, p, NULL,
203 "Printer driver directory \"%s\" not available.", temp);
204 }
205 else
206 cupsdLogMessage(CUPSD_LOG_ERROR,
207 "Program directory \"%s\" not available: %s", temp,
208 strerror(errno));
209
210 return (0);
211 }
212
213 if (fileinfo.st_uid || /* 1. Must be owned by root */
214 #ifdef __APPLE__
215 ((fileinfo.st_mode & S_IWGRP) && fileinfo.st_gid &&
216 fileinfo.st_gid != 80) || /* 2. Must not be writable by group */
217 #else
218 ((fileinfo.st_mode & S_IWGRP) && fileinfo.st_gid) ||
219 /* 2. Must not be writable by group */
220 #endif /* __APPLE__ */
221 (fileinfo.st_mode & S_ISUID) || /* 3. Must not be setuid */
222 (fileinfo.st_mode & S_IWOTH)) /* 4. Must not be writable by others */
223 {
224 if (p)
225 {
226 snprintf(p->state_message, sizeof(p->state_message),
227 "Printer driver directory \"%s\" has insecure permissions "
228 "(0%o/uid=%d/gid=%d).", temp, fileinfo.st_mode,
229 (int)fileinfo.st_uid, (int)fileinfo.st_gid);
230
231 cupsdLogMessage(CUPSD_LOG_ERROR, "%s: %s", p->name, p->state_message);
232
233 if (cupsdSetPrinterReasons(p, "+cups-insecure-filter-warning"))
234 cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, p, NULL, "%s",
235 p->state_message);
236 }
237 else
238 cupsdLogMessage(CUPSD_LOG_ERROR,
239 "Program directory \"%s\" has insecure permissions "
240 "(0%o/uid=%d/gid=%d).", temp, fileinfo.st_mode,
241 (int)fileinfo.st_uid, (int)fileinfo.st_gid);
242
243 errno = EPERM;
244
245 return (0);
246 }
247
248 cupsdLogMessage(CUPSD_LOG_DEBUG2,
249 "%s%s directory \"%s\" permissions OK "
250 "(0%o/uid=%d/gid=%d).", p ? p->name : "",
251 p ? ": Printer driver" : "Program", temp,
252 fileinfo.st_mode, (int)fileinfo.st_uid,
253 (int)fileinfo.st_gid);
254
255 /*
256 * If we get here then we can "safely" run this program...
257 */
258
259 return (1);
260 }
261
262
263 /*
264 * 'cupsdCreateProfile()' - Create an execution profile for a subprocess.
265 */
266
267 void * /* O - Profile or NULL on error */
268 cupsdCreateProfile(int job_id) /* I - Job ID or 0 for none */
269 {
270 #ifdef HAVE_SANDBOX_H
271 cups_file_t *fp; /* File pointer */
272 char profile[1024], /* File containing the profile */
273 cache[1024], /* Quoted CacheDir */
274 request[1024], /* Quoted RequestRoot */
275 root[1024], /* Quoted ServerRoot */
276 temp[1024]; /* Quoted TempDir */
277
278
279 if (!UseProfiles)
280 {
281 /*
282 * Only use sandbox profiles as root...
283 */
284
285 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCreateProfile(job_id=%d) = NULL",
286 job_id);
287
288 return (NULL);
289 }
290
291 if ((fp = cupsTempFile2(profile, sizeof(profile))) == NULL)
292 {
293 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCreateProfile(job_id=%d) = NULL",
294 job_id);
295 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create security profile: %s",
296 strerror(errno));
297 return (NULL);
298 }
299
300 fchown(cupsFileNumber(fp), RunUser, Group);
301 fchmod(cupsFileNumber(fp), 0640);
302
303 cupsd_requote(cache, CacheDir, sizeof(cache));
304 cupsd_requote(request, RequestRoot, sizeof(request));
305 cupsd_requote(root, ServerRoot, sizeof(root));
306 cupsd_requote(temp, TempDir, sizeof(temp));
307
308 cupsFilePuts(fp, "(version 1)\n");
309 if (LogLevel >= CUPSD_LOG_DEBUG)
310 cupsFilePuts(fp, "(debug deny)\n");
311 cupsFilePuts(fp, "(allow default)\n");
312 cupsFilePrintf(fp,
313 "(deny file-write* file-read-data file-read-metadata\n"
314 " (regex"
315 " #\"^%s$\"" /* RequestRoot */
316 " #\"^%s/\"" /* RequestRoot/... */
317 "))\n",
318 request, request);
319 if (!RunUser)
320 cupsFilePuts(fp,
321 "(deny file-write* file-read-data file-read-metadata\n"
322 " (regex"
323 " #\"^/Users$\""
324 " #\"^/Users/\""
325 "))\n");
326 cupsFilePrintf(fp,
327 "(deny file-write*\n"
328 " (regex"
329 " #\"^%s$\"" /* ServerRoot */
330 " #\"^%s/\"" /* ServerRoot/... */
331 " #\"^/private/etc$\""
332 " #\"^/private/etc/\""
333 " #\"^/usr/local/etc$\""
334 " #\"^/usr/local/etc/\""
335 " #\"^/Library$\""
336 " #\"^/Library/\""
337 " #\"^/System$\""
338 " #\"^/System/\""
339 "))\n",
340 root, root);
341 /* Specifically allow applications to stat RequestRoot */
342 cupsFilePrintf(fp,
343 "(allow file-read-metadata\n"
344 " (regex"
345 " #\"^%s$\"" /* RequestRoot */
346 "))\n",
347 request);
348 cupsFilePrintf(fp,
349 "(allow file-write* file-read-data file-read-metadata\n"
350 " (regex"
351 " #\"^%s$\"" /* TempDir */
352 " #\"^%s/\"" /* TempDir/... */
353 " #\"^%s$\"" /* CacheDir */
354 " #\"^%s/\"" /* CacheDir/... */
355 " #\"^%s/Library$\"" /* RequestRoot/Library */
356 " #\"^%s/Library/\"" /* RequestRoot/Library/... */
357 " #\"^/Library/Application Support/\""
358 " #\"^/Library/Caches/\""
359 " #\"^/Library/Preferences/\""
360 " #\"^/Library/Printers/.*/\""
361 " #\"^/Users/Shared/\""
362 "))\n",
363 temp, temp, cache, cache, request, request);
364 cupsFilePuts(fp,
365 "(deny file-write*\n"
366 " (regex"
367 " #\"^/Library/Printers/PPDs$\""
368 " #\"^/Library/Printers/PPDs/\""
369 " #\"^/Library/Printers/PPD Plugins$\""
370 " #\"^/Library/Printers/PPD Plugins/\""
371 "))\n");
372 if (job_id)
373 {
374 /*
375 * Allow job filters to read the spool file(s)...
376 */
377
378 cupsFilePrintf(fp,
379 "(allow file-read-data file-read-metadata\n"
380 " (regex #\"^%s/([ac]%05d|d%05d-[0-9][0-9][0-9])$\"))\n",
381 request, job_id, job_id);
382 }
383 else
384 {
385 /*
386 * Allow email notifications from notifiers...
387 */
388
389 cupsFilePuts(fp,
390 "(allow process-exec\n"
391 " (literal \"/usr/sbin/sendmail\")\n"
392 " (with no-sandbox)\n"
393 ")\n");
394 }
395
396 cupsFileClose(fp);
397
398 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCreateProfile(job_id=%d) = \"%s\"",
399 job_id, profile);
400 return ((void *)strdup(profile));
401
402 #else
403 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCreateProfile(job_id=%d) = NULL",
404 job_id);
405
406 return (NULL);
407 #endif /* HAVE_SANDBOX_H */
408 }
409
410
411 /*
412 * 'cupsdDestroyProfile()' - Delete an execution profile.
413 */
414
415 void
416 cupsdDestroyProfile(void *profile) /* I - Profile */
417 {
418 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDeleteProfile(profile=\"%s\")",
419 profile ? (char *)profile : "(null)");
420
421 #ifdef HAVE_SANDBOX_H
422 if (profile)
423 {
424 unlink((char *)profile);
425 free(profile);
426 }
427 #endif /* HAVE_SANDBOX_H */
428 }
429
430
431 /*
432 * 'cupsdEndProcess()' - End a process.
433 */
434
435 int /* O - 0 on success, -1 on failure */
436 cupsdEndProcess(int pid, /* I - Process ID */
437 int force) /* I - Force child to die */
438 {
439 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdEndProcess(pid=%d, force=%d)", pid,
440 force);
441
442 if (!pid)
443 return (0);
444 else if (force)
445 return (kill(pid, SIGKILL));
446 else
447 return (kill(pid, SIGTERM));
448 }
449
450
451 /*
452 * 'cupsdFinishProcess()' - Finish a process and get its name.
453 */
454
455 const char * /* O - Process name */
456 cupsdFinishProcess(int pid, /* I - Process ID */
457 char *name, /* I - Name buffer */
458 int namelen, /* I - Size of name buffer */
459 int *job_id) /* O - Job ID pointer or NULL */
460 {
461 cupsd_proc_t key, /* Search key */
462 *proc; /* Matching process */
463
464
465 key.pid = pid;
466
467 if ((proc = (cupsd_proc_t *)cupsArrayFind(process_array, &key)) != NULL)
468 {
469 if (job_id)
470 *job_id = proc->job_id;
471
472 strlcpy(name, proc->name, namelen);
473 cupsArrayRemove(process_array, proc);
474 free(proc);
475 }
476 else
477 {
478 if (job_id)
479 *job_id = 0;
480
481 strlcpy(name, "unknown", namelen);
482 }
483
484 cupsdLogMessage(CUPSD_LOG_DEBUG2,
485 "cupsdFinishProcess(pid=%d, name=%p, namelen=%d, "
486 "job_id=%p(%d)) = \"%s\"", pid, name, namelen, job_id,
487 job_id ? *job_id : 0, name);
488
489 return (name);
490 }
491
492
493 /*
494 * 'cupsdStartProcess()' - Start a process.
495 */
496
497 int /* O - Process ID or 0 */
498 cupsdStartProcess(
499 const char *command, /* I - Full path to command */
500 char *argv[], /* I - Command-line arguments */
501 char *envp[], /* I - Environment */
502 int infd, /* I - Standard input file descriptor */
503 int outfd, /* I - Standard output file descriptor */
504 int errfd, /* I - Standard error file descriptor */
505 int backfd, /* I - Backchannel file descriptor */
506 int sidefd, /* I - Sidechannel file descriptor */
507 int root, /* I - Run as root? */
508 void *profile, /* I - Security profile to use */
509 cupsd_job_t *job, /* I - Job associated with process */
510 int *pid) /* O - Process ID */
511 {
512 int i; /* Looping var */
513 const char *exec_path = command; /* Command to be exec'd */
514 char *real_argv[103], /* Real command-line arguments */
515 cups_exec[1024]; /* Path to "cups-exec" program */
516 int user; /* Command UID */
517 cupsd_proc_t *proc; /* New process record */
518 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
519 struct sigaction action; /* POSIX signal handler */
520 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
521 #if defined(__APPLE__)
522 char processPath[1024], /* CFProcessPath environment variable */
523 linkpath[1024]; /* Link path for symlinks... */
524 int linkbytes; /* Bytes for link path */
525 #endif /* __APPLE__ */
526
527
528 *pid = 0;
529
530 /*
531 * Figure out the UID for the child process...
532 */
533
534 if (RunUser)
535 user = RunUser;
536 else if (root)
537 user = 0;
538 else
539 user = User;
540
541 /*
542 * Check the permissions of the command we are running...
543 */
544
545 if (!cupsdCheckProgram(command, job ? job->printer : NULL))
546 return (0);
547
548 #if defined(__APPLE__)
549 if (envp)
550 {
551 /*
552 * Add special voodoo magic for Mac OS X - this allows Mac OS X
553 * programs to access their bundle resources properly...
554 */
555
556 if ((linkbytes = readlink(command, linkpath, sizeof(linkpath) - 1)) > 0)
557 {
558 /*
559 * Yes, this is a symlink to the actual program, nul-terminate and
560 * use it...
561 */
562
563 linkpath[linkbytes] = '\0';
564
565 if (linkpath[0] == '/')
566 snprintf(processPath, sizeof(processPath), "CFProcessPath=%s",
567 linkpath);
568 else
569 snprintf(processPath, sizeof(processPath), "CFProcessPath=%s/%s",
570 dirname((char *)command), linkpath);
571 }
572 else
573 snprintf(processPath, sizeof(processPath), "CFProcessPath=%s", command);
574
575 envp[0] = processPath; /* Replace <CFProcessPath> string */
576 }
577 #endif /* __APPLE__ */
578
579 /*
580 * Use helper program when we have a sandbox profile...
581 */
582
583 if (profile)
584 {
585 snprintf(cups_exec, sizeof(cups_exec), "%s/daemon/cups-exec", ServerBin);
586
587 real_argv[0] = cups_exec;
588 real_argv[1] = profile;
589 real_argv[2] = (char *)command;
590
591 for (i = 0;
592 i < (int)(sizeof(real_argv) / sizeof(real_argv[0]) - 4) && argv[i];
593 i ++)
594 real_argv[i + 3] = argv[i];
595
596 real_argv[i + 3] = NULL;
597
598 argv = real_argv;
599 exec_path = cups_exec;
600 }
601
602 /*
603 * Block signals before forking...
604 */
605
606 cupsdHoldSignals();
607
608 if ((*pid = fork()) == 0)
609 {
610 /*
611 * Child process goes here...
612 *
613 * Update stdin/stdout/stderr as needed...
614 */
615
616 if (infd != 0)
617 {
618 if (infd < 0)
619 infd = open("/dev/null", O_RDONLY);
620
621 if (infd != 0)
622 {
623 dup2(infd, 0);
624 close(infd);
625 }
626 }
627
628 if (outfd != 1)
629 {
630 if (outfd < 0)
631 outfd = open("/dev/null", O_WRONLY);
632
633 if (outfd != 1)
634 {
635 dup2(outfd, 1);
636 close(outfd);
637 }
638 }
639
640 if (errfd != 2)
641 {
642 if (errfd < 0)
643 errfd = open("/dev/null", O_WRONLY);
644
645 if (errfd != 2)
646 {
647 dup2(errfd, 2);
648 close(errfd);
649 }
650 }
651
652 if (backfd != 3 && backfd >= 0)
653 {
654 dup2(backfd, 3);
655 close(backfd);
656 fcntl(3, F_SETFL, O_NDELAY);
657 }
658
659 if (sidefd != 4 && sidefd >= 0)
660 {
661 dup2(sidefd, 4);
662 close(sidefd);
663 fcntl(4, F_SETFL, O_NDELAY);
664 }
665
666 /*
667 * Change the priority of the process based on the FilterNice setting.
668 * (this is not done for root processes...)
669 */
670
671 if (!root)
672 nice(FilterNice);
673
674 /*
675 * Change user to something "safe"...
676 */
677
678 if (!root && !RunUser)
679 {
680 /*
681 * Running as root, so change to non-priviledged user...
682 */
683
684 if (setgid(Group))
685 exit(errno);
686
687 if (setgroups(1, &Group))
688 exit(errno);
689
690 if (setuid(User))
691 exit(errno);
692 }
693 else
694 {
695 /*
696 * Reset group membership to just the main one we belong to.
697 */
698
699 if (setgid(Group) && !RunUser)
700 exit(errno);
701
702 if (setgroups(1, &Group) && !RunUser)
703 exit(errno);
704 }
705
706 /*
707 * Change umask to restrict permissions on created files...
708 */
709
710 umask(077);
711
712 /*
713 * Unblock signals before doing the exec...
714 */
715
716 #ifdef HAVE_SIGSET
717 sigset(SIGTERM, SIG_DFL);
718 sigset(SIGCHLD, SIG_DFL);
719 sigset(SIGPIPE, SIG_DFL);
720 #elif defined(HAVE_SIGACTION)
721 memset(&action, 0, sizeof(action));
722
723 sigemptyset(&action.sa_mask);
724 action.sa_handler = SIG_DFL;
725
726 sigaction(SIGTERM, &action, NULL);
727 sigaction(SIGCHLD, &action, NULL);
728 sigaction(SIGPIPE, &action, NULL);
729 #else
730 signal(SIGTERM, SIG_DFL);
731 signal(SIGCHLD, SIG_DFL);
732 signal(SIGPIPE, SIG_DFL);
733 #endif /* HAVE_SIGSET */
734
735 cupsdReleaseSignals();
736
737 /*
738 * Execute the command; if for some reason this doesn't work, log an error
739 * exit with a non-zero value...
740 */
741
742 if (envp)
743 execve(exec_path, argv, envp);
744 else
745 execv(exec_path, argv);
746
747 perror(command);
748
749 exit(1);
750 }
751 else if (*pid < 0)
752 {
753 /*
754 * Error - couldn't fork a new process!
755 */
756
757 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to fork %s - %s.", command,
758 strerror(errno));
759
760 *pid = 0;
761 }
762 else
763 {
764 if (!process_array)
765 process_array = cupsArrayNew((cups_array_func_t)compare_procs, NULL);
766
767 if (process_array)
768 {
769 if ((proc = calloc(1, sizeof(cupsd_proc_t) + strlen(command))) != NULL)
770 {
771 proc->pid = *pid;
772 proc->job_id = job ? job->id : 0;
773 _cups_strcpy(proc->name, command);
774
775 cupsArrayAdd(process_array, proc);
776 }
777 }
778 }
779
780 cupsdReleaseSignals();
781
782 cupsdLogMessage(CUPSD_LOG_DEBUG2,
783 "cupsdStartProcess(command=\"%s\", argv=%p, envp=%p, "
784 "infd=%d, outfd=%d, errfd=%d, backfd=%d, sidefd=%d, root=%d, "
785 "profile=%p, job=%p(%d), pid=%p) = %d",
786 command, argv, envp, infd, outfd, errfd, backfd, sidefd,
787 root, profile, job, job ? job->id : 0, pid, *pid);
788
789 return (*pid);
790 }
791
792
793 /*
794 * 'compare_procs()' - Compare two processes.
795 */
796
797 static int /* O - Result of comparison */
798 compare_procs(cupsd_proc_t *a, /* I - First process */
799 cupsd_proc_t *b) /* I - Second process */
800 {
801 return (a->pid - b->pid);
802 }
803
804
805 #ifdef HAVE_SANDBOX_H
806 /*
807 * 'cupsd_requote()' - Make a regular-expression version of a string.
808 */
809
810 static char * /* O - Quoted string */
811 cupsd_requote(char *dst, /* I - Destination buffer */
812 const char *src, /* I - Source string */
813 size_t dstsize) /* I - Size of destination buffer */
814 {
815 int ch; /* Current character */
816 char *dstptr, /* Current position in buffer */
817 *dstend; /* End of destination buffer */
818
819
820 dstptr = dst;
821 dstend = dst + dstsize - 2;
822
823 while (*src && dstptr < dstend)
824 {
825 ch = *src++;
826
827 if (strchr(".?*()[]^$\\", ch))
828 *dstptr++ = '\\';
829
830 *dstptr++ = ch;
831 }
832
833 *dstptr = '\0';
834
835 return (dst);
836 }
837 #endif /* HAVE_SANDBOX_H */
838
839
840 /*
841 * End of "$Id$".
842 */