]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/util.c
Limit size of chunked requests (<rdar://problem/23132353>)
[thirdparty/cups.git] / scheduler / util.c
CommitLineData
ef416fc2 1/*
f2d18633 2 * "$Id$"
ef416fc2 3 *
7e86f2f6 4 * Mini-daemon utility functions for CUPS.
ef416fc2 5 *
7e86f2f6
MS
6 * Copyright 2007-2014 by Apple Inc.
7 * Copyright 1997-2005 by Easy Software Products.
ef416fc2 8 *
7e86f2f6
MS
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/".
ef416fc2 14 */
15
16/*
17 * Include necessary headers...
18 */
19
20#include "util.h"
c934a06c
MS
21#include <unistd.h>
22#include <sys/stat.h>
23#include <fcntl.h>
24#ifdef __APPLE__
25# include <libgen.h>
26extern char **environ;
88f9aafc 27#endif /* __APPLE__ */
ef416fc2 28
29
30/*
31 * 'cupsdCompareNames()' - Compare two names.
32 *
88f9aafc 33 * This function basically does a _cups_strcasecmp() of the two strings,
ef416fc2 34 * but is also aware of numbers so that "a2" < "a100".
35 */
36
37int /* O - Result of comparison */
38cupsdCompareNames(const char *s, /* I - First string */
39 const char *t) /* I - Second string */
40{
41 int diff, /* Difference between digits */
42 digits; /* Number of digits */
43
44
45 /*
46 * Loop through both names, returning only when a difference is
47 * seen. Also, compare whole numbers rather than just characters, too!
48 */
49
50 while (*s && *t)
51 {
52 if (isdigit(*s & 255) && isdigit(*t & 255))
53 {
54 /*
55 * Got a number; start by skipping leading 0's...
56 */
57
58 while (*s == '0')
59 s ++;
60 while (*t == '0')
61 t ++;
62
63 /*
64 * Skip equal digits...
65 */
66
67 while (isdigit(*s & 255) && *s == *t)
68 {
69 s ++;
70 t ++;
71 }
72
73 /*
74 * Bounce out if *s and *t aren't both digits...
75 */
76
77 if (isdigit(*s & 255) && !isdigit(*t & 255))
78 return (1);
79 else if (!isdigit(*s & 255) && isdigit(*t & 255))
80 return (-1);
81 else if (!isdigit(*s & 255) || !isdigit(*t & 255))
88f9aafc 82 continue;
ef416fc2 83
84 if (*s < *t)
85 diff = -1;
86 else
87 diff = 1;
88
89 /*
90 * Figure out how many more digits there are...
91 */
92
93 digits = 0;
94 s ++;
95 t ++;
96
97 while (isdigit(*s & 255))
98 {
99 digits ++;
100 s ++;
101 }
102
103 while (isdigit(*t & 255))
104 {
105 digits --;
106 t ++;
107 }
108
109 /*
110 * Return if the number or value of the digits is different...
111 */
112
113 if (digits < 0)
114 return (-1);
115 else if (digits > 0)
116 return (1);
117 else if (diff)
118 return (diff);
119 }
120 else if (tolower(*s) < tolower(*t))
121 return (-1);
122 else if (tolower(*s) > tolower(*t))
123 return (1);
124 else
125 {
126 s ++;
127 t ++;
128 }
129 }
130
131 /*
132 * Return the results of the final comparison...
133 */
134
135 if (*s)
136 return (1);
137 else if (*t)
138 return (-1);
139 else
140 return (0);
141}
142
143
ed6e7faf
MS
144/*
145 * 'cupsdCreateStringsArray()' - Create a CUPS array of strings.
146 */
147
148cups_array_t * /* O - CUPS array */
149cupsdCreateStringsArray(const char *s) /* I - Comma-delimited strings */
150{
eac3a0a0 151 if (!s || !*s)
ed6e7faf 152 return (NULL);
eac3a0a0 153 else
5a9febac 154 return (_cupsArrayNewStrings(s, ','));
ed6e7faf
MS
155}
156
157
c934a06c
MS
158/*
159 * 'cupsdExec()' - Run a program with the correct environment.
160 *
f3c17241 161 * On OS X, we need to update the CFProcessPath environment variable that
c934a06c
MS
162 * is passed in the environment so the child can access its bundled resources.
163 */
164
165int /* O - exec() status */
166cupsdExec(const char *command, /* I - Full path to program */
167 char **argv) /* I - Command-line arguments */
168{
169#ifdef __APPLE__
170 int i, j; /* Looping vars */
171 char *envp[500], /* Array of environment variables */
172 cfprocesspath[1024], /* CFProcessPath environment variable */
173 linkpath[1024]; /* Link path for symlinks... */
174 int linkbytes; /* Bytes for link path */
175
176
177 /*
f3c17241 178 * Some OS X programs are bundled and need the CFProcessPath environment
c934a06c
MS
179 * variable defined. If the command is a symlink, resolve the link and point
180 * to the resolved location, otherwise, use the command path itself.
181 */
182
183 if ((linkbytes = readlink(command, linkpath, sizeof(linkpath) - 1)) > 0)
184 {
185 /*
186 * Yes, this is a symlink to the actual program, nul-terminate and
187 * use it...
188 */
189
190 linkpath[linkbytes] = '\0';
191
192 if (linkpath[0] == '/')
193 snprintf(cfprocesspath, sizeof(cfprocesspath), "CFProcessPath=%s",
194 linkpath);
195 else
196 snprintf(cfprocesspath, sizeof(cfprocesspath), "CFProcessPath=%s/%s",
197 dirname((char *)command), linkpath);
198 }
199 else
200 snprintf(cfprocesspath, sizeof(cfprocesspath), "CFProcessPath=%s", command);
201
202 envp[0] = cfprocesspath;
203
204 /*
205 * Copy the rest of the environment except for any CFProcessPath that may
206 * already be there...
207 */
208
209 for (i = 1, j = 0;
210 environ[j] && i < (int)(sizeof(envp) / sizeof(envp[0]) - 1);
211 j ++)
212 if (strncmp(environ[j], "CFProcessPath=", 14))
213 envp[i ++] = environ[j];
214
215 envp[i] = NULL;
216
217 /*
218 * Use execve() to run the program...
219 */
220
221 return (execve(command, argv, envp));
222
223#else
224 /*
225 * On other operating systems, just call execv() to use the same environment
226 * variables as the parent...
227 */
228
229 return (execv(command, argv));
230#endif /* __APPLE__ */
231}
232
233
234/*
235 * 'cupsdPipeCommand()' - Read output from a command.
236 */
237
238cups_file_t * /* O - CUPS file or NULL on error */
239cupsdPipeCommand(int *pid, /* O - Process ID or 0 on error */
240 const char *command, /* I - Command to run */
241 char **argv, /* I - Arguments to pass to command */
7e86f2f6 242 uid_t user) /* I - User to run as or 0 for current */
c934a06c 243{
97c9a8d7
MS
244 int fd, /* Temporary file descriptor */
245 fds[2]; /* Pipe file descriptors */
c934a06c
MS
246
247
248 /*
249 * First create the pipe...
250 */
251
252 if (pipe(fds))
253 {
254 *pid = 0;
255 return (NULL);
256 }
257
258 /*
259 * Set the "close on exec" flag on each end of the pipe...
260 */
261
262 if (fcntl(fds[0], F_SETFD, fcntl(fds[0], F_GETFD) | FD_CLOEXEC))
263 {
264 close(fds[0]);
265 close(fds[1]);
266
267 *pid = 0;
268
269 return (NULL);
270 }
271
272 if (fcntl(fds[1], F_SETFD, fcntl(fds[1], F_GETFD) | FD_CLOEXEC))
273 {
274 close(fds[0]);
275 close(fds[1]);
276
277 *pid = 0;
278
279 return (NULL);
280 }
281
282 /*
283 * Then run the command...
284 */
285
286 if ((*pid = fork()) < 0)
287 {
288 /*
289 * Unable to fork!
290 */
291
292 *pid = 0;
293 close(fds[0]);
294 close(fds[1]);
295
296 return (NULL);
297 }
298 else if (!*pid)
299 {
300 /*
301 * Child comes here...
302 */
303
304 if (!getuid() && user)
305 setuid(user); /* Run as restricted user */
306
97c9a8d7
MS
307 if ((fd = open("/dev/null", O_RDONLY)) > 0)
308 {
309 dup2(fd, 0); /* </dev/null */
310 close(fd);
311 }
c934a06c 312
97c9a8d7
MS
313 dup2(fds[1], 1); /* >pipe */
314 close(fds[1]);
c934a06c
MS
315
316 cupsdExec(command, argv);
317 exit(errno);
318 }
319
320 /*
321 * Parent comes here, open the input side of the pipe...
322 */
323
324 close(fds[1]);
325
326 return (cupsFileOpenFd(fds[0], "r"));
327}
328
329
ef416fc2 330/*
331 * 'cupsdSendIPPGroup()' - Send a group tag.
332 */
333
334void
335cupsdSendIPPGroup(ipp_tag_t group_tag) /* I - Group tag */
336{
337 /*
338 * Send IPP group tag (1 byte)...
339 */
340
341 putchar(group_tag);
342}
343
344
345/*
346 * 'cupsdSendIPPHeader()' - Send the IPP response header.
347 */
348
349void
350cupsdSendIPPHeader(
351 ipp_status_t status_code, /* I - Status code */
352 int request_id) /* I - Request ID */
353{
354 /*
355 * Send IPP/1.1 response header: version number (2 bytes), status code
356 * (2 bytes), and request ID (4 bytes)...
94da7e34
MS
357 *
358 * TODO: Add version number (IPP/2.x and IPP/1.0) support.
ef416fc2 359 */
360
361 putchar(1);
362 putchar(1);
363
364 putchar(status_code >> 8);
365 putchar(status_code);
366
367 putchar(request_id >> 24);
368 putchar(request_id >> 16);
369 putchar(request_id >> 8);
370 putchar(request_id);
371}
372
373
374/*
375 * 'cupsdSendIPPInteger()' - Send an integer attribute.
376 */
377
378void
379cupsdSendIPPInteger(
380 ipp_tag_t value_tag, /* I - Value tag */
381 const char *name, /* I - Attribute name */
382 int value) /* I - Attribute value */
383{
384 size_t len; /* Length of attribute name */
385
386
387 /*
388 * Send IPP integer value: value tag (1 byte), name length (2 bytes),
3d8365b8 389 * name string (without nul), value length (2 bytes), and value (4 bytes)...
ef416fc2 390 */
391
392 putchar(value_tag);
393
394 len = strlen(name);
7e86f2f6
MS
395 putchar((int)(len >> 8));
396 putchar((int)len);
ef416fc2 397
398 fputs(name, stdout);
399
3d8365b8 400 putchar(0);
401 putchar(4);
402
ef416fc2 403 putchar(value >> 24);
404 putchar(value >> 16);
405 putchar(value >> 8);
406 putchar(value);
407}
408
409
410/*
411 * 'cupsdSendIPPString()' - Send a string attribute.
412 */
413
414void
415cupsdSendIPPString(
416 ipp_tag_t value_tag, /* I - Value tag */
417 const char *name, /* I - Attribute name */
418 const char *value) /* I - Attribute value */
419{
420 size_t len; /* Length of attribute name */
421
422
423 /*
424 * Send IPP string value: value tag (1 byte), name length (2 bytes),
425 * name string (without nul), value length (2 bytes), and value string
426 * (without nul)...
427 */
428
429 putchar(value_tag);
430
431 len = strlen(name);
7e86f2f6
MS
432 putchar((int)(len >> 8));
433 putchar((int)len);
ef416fc2 434
435 fputs(name, stdout);
436
437 len = strlen(value);
7e86f2f6
MS
438 putchar((int)(len >> 8));
439 putchar((int)len);
ef416fc2 440
441 fputs(value, stdout);
442}
443
444
445/*
446 * 'cupsdSendIPPTrailer()' - Send the end-of-message tag.
447 */
448
449void
450cupsdSendIPPTrailer(void)
451{
452 putchar(IPP_TAG_END);
453 fflush(stdout);
454}
455
456
457/*
f2d18633 458 * End of "$Id$".
ef416fc2 459 */