• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Sandbox helper for CUPS.
3  *
4  * Copyright © 2020-2024 by OpenPrinting.
5  * Copyright © 2007-2014 by Apple Inc.
6  *
7  * Licensed under Apache License v2.0.  See the file "LICENSE" for more
8  * information.
9  *
10  * Usage:
11  *
12  *     cups-exec /path/to/profile [-u UID] [-g GID] [-n NICE] /path/to/program argv0 argv1 ... argvN
13  */
14 
15 /*
16  * Include necessary headers...
17  */
18 
19 #include <cups/string-private.h>
20 #include <cups/file.h>
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <grp.h>
24 #include <sys/stat.h>
25 #ifdef HAVE_SANDBOX_H
26 #  include <sandbox.h>
27 #  ifndef SANDBOX_NAMED_EXTERNAL
28 #    define SANDBOX_NAMED_EXTERNAL  0x0003
29 #  endif /* !SANDBOX_NAMED_EXTERNAL */
30 #  pragma GCC diagnostic ignored "-Wdeprecated-declarations"
31 #endif /* HAVE_SANDBOX_H */
32 
33 
34 /*
35  * Local functions...
36  */
37 
38 static void	usage(void) _CUPS_NORETURN;
39 
40 
41 /*
42  * 'main()' - Apply sandbox profile and execute program.
43  */
44 
45 int					/* O - Exit status */
main(int argc,char * argv[])46 main(int  argc,				/* I - Number of command-line args */
47      char *argv[])			/* I - Command-line arguments */
48 {
49   int		i;			/* Looping var */
50   const char	*opt;			/* Current option character */
51   uid_t		uid = getuid();		/* UID */
52   gid_t		gid = getgid();		/* GID */
53   int		niceval = 0;		/* Nice value */
54 #ifdef HAVE_SANDBOX_H
55   char		*sandbox_error = NULL;	/* Sandbox error, if any */
56 #endif /* HAVE_SANDBOX_H */
57 
58 
59  /*
60   * Parse command-line...
61   */
62 
63   for (i = 1; i < argc; i ++)
64   {
65     if (argv[i][0] == '-')
66     {
67       for (opt = argv[i] + 1; *opt; opt ++)
68       {
69         switch (*opt)
70         {
71           case 'g' : /* -g gid */
72               i ++;
73               if (i >= argc)
74                 usage();
75 
76               gid = (gid_t)strtoul(argv[i], NULL, 10);
77               break;
78 
79           case 'n' : /* -n nice-value */
80               i ++;
81               if (i >= argc)
82                 usage();
83 
84               niceval = atoi(argv[i]);
85               break;
86 
87           case 'u' : /* -g gid */
88               i ++;
89               if (i >= argc)
90                 usage();
91 
92               uid = (uid_t)strtoul(argv[i], NULL, 10);
93               break;
94 
95 	  default :
96 	      fprintf(stderr, "cups-exec: Unknown option '-%c'.\n", *opt);
97 	      usage();
98         }
99       }
100     }
101     else
102       break;
103   }
104 
105  /*
106   * Check that we have enough arguments...
107   */
108 
109   if ((i + 3) > argc)
110   {
111     fputs("cups-exec: Insufficient arguments.\n", stderr);
112     usage();
113   }
114 
115  /*
116   * Make sure side and back channel FDs are non-blocking...
117   */
118 
119   fcntl(3, F_SETFL, O_NDELAY);
120   fcntl(4, F_SETFL, O_NDELAY);
121 
122  /*
123   * Change UID, GID, and nice value...
124   */
125 
126   if (uid)
127     nice(niceval);
128 
129   if (!getuid())
130   {
131     if (setgid(gid))
132       exit(errno + 100);
133 
134 #  if CUPS_SNAP
135     if (setgroups(0, NULL))
136 #  else
137     if (setgroups(1, &gid))
138 #  endif /* CUPS_SNAP */
139       exit(errno + 100);
140 
141     if (uid && setuid(uid))
142       exit(errno + 100);
143   }
144 
145   umask(077);
146 
147 #ifdef HAVE_SANDBOX_H
148  /*
149   * Run in a separate security profile...
150   */
151 
152   if (strcmp(argv[i], "none") &&
153       sandbox_init(argv[i], SANDBOX_NAMED_EXTERNAL, &sandbox_error))
154   {
155     cups_file_t	*fp;			/* File */
156     char	line[1024];		/* Line from file */
157     unsigned	linenum = 0;		/* Line number in file */
158 
159     fprintf(stderr, "DEBUG: sandbox_init failed: %s (%s)\n", sandbox_error,
160 	    strerror(errno));
161     sandbox_free_error(sandbox_error);
162 
163     if ((fp = cupsFileOpen(argv[i], "r")) != NULL)
164     {
165       while (cupsFileGets(fp, line, sizeof(line)))
166       {
167         linenum ++;
168         fprintf(stderr, "DEBUG: %4u  %s\n", linenum, line);
169       }
170       cupsFileClose(fp);
171     }
172 
173     return (100 + EINVAL);
174   }
175 #endif /* HAVE_SANDBOX_H */
176 
177  /*
178   * Execute the program...
179   */
180 
181   execv(argv[i + 1], argv + i + 2);
182 
183  /*
184   * If we get here, execv() failed...
185   */
186 
187   fprintf(stderr, "DEBUG: execv failed: %s\n", strerror(errno));
188   return (errno + 100);
189 }
190 
191 
192 /*
193  * 'usage()' - Show program usage.
194  */
195 
196 static void
usage(void)197 usage(void)
198 {
199   fputs("Usage: cups-exec [-g gid] [-n nice-value] [-u uid] /path/to/profile /path/to/program argv0 argv1 ... argvN\n", stderr);
200   exit(1);
201 }
202