]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/cert.c
Cleanup some DEBUG2 log messages (<rdar://problem/23135122>)
[thirdparty/cups.git] / scheduler / cert.c
1 /*
2 * "$Id$"
3 *
4 * Authentication certificate routines for the CUPS scheduler.
5 *
6 * Copyright 2007-2015 by Apple Inc.
7 * Copyright 1997-2006 by Easy Software Products.
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
16 /*
17 * Include necessary headers...
18 */
19
20 #include "cupsd.h"
21 #ifdef HAVE_ACL_INIT
22 # include <sys/acl.h>
23 # ifdef HAVE_MEMBERSHIP_H
24 # include <membership.h>
25 # endif /* HAVE_MEMBERSHIP_H */
26 #endif /* HAVE_ACL_INIT */
27
28
29 /*
30 * Local functions...
31 */
32
33 static int ctcompare(const char *a, const char *b);
34
35
36 /*
37 * 'cupsdAddCert()' - Add a certificate.
38 */
39
40 void
41 cupsdAddCert(int pid, /* I - Process ID */
42 const char *username, /* I - Username */
43 int type) /* I - AuthType for username */
44 {
45 int i; /* Looping var */
46 cupsd_cert_t *cert; /* Current certificate */
47 int fd; /* Certificate file */
48 char filename[1024]; /* Certificate filename */
49 static const char hex[] = "0123456789ABCDEF";
50 /* Hex constants... */
51
52
53 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAddCert: Adding certificate for PID %d", pid);
54
55 /*
56 * Allocate memory for the certificate...
57 */
58
59 if ((cert = calloc(sizeof(cupsd_cert_t), 1)) == NULL)
60 return;
61
62 /*
63 * Fill in the certificate information...
64 */
65
66 cert->pid = pid;
67 cert->type = type;
68 strlcpy(cert->username, username, sizeof(cert->username));
69
70 for (i = 0; i < 32; i ++)
71 cert->certificate[i] = hex[CUPS_RAND() & 15];
72
73 /*
74 * Save the certificate to a file readable only by the User and Group
75 * (or root and SystemGroup for PID == 0)...
76 */
77
78 snprintf(filename, sizeof(filename), "%s/certs/%d", StateDir, pid);
79 unlink(filename);
80
81 if ((fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0400)) < 0)
82 {
83 cupsdLogMessage(CUPSD_LOG_ERROR,
84 "Unable to create certificate file %s - %s",
85 filename, strerror(errno));
86 free(cert);
87 return;
88 }
89
90 if (pid == 0)
91 {
92 #ifdef HAVE_ACL_INIT
93 acl_t acl; /* ACL information */
94 acl_entry_t entry; /* ACL entry */
95 acl_permset_t permset; /* Permissions */
96 # ifdef HAVE_MBR_UID_TO_UUID
97 uuid_t group; /* Group ID */
98 # endif /* HAVE_MBR_UID_TO_UUID */
99 static int acls_not_supported = 0;
100 /* Only warn once */
101 #endif /* HAVE_ACL_INIT */
102
103
104 /*
105 * Root certificate...
106 */
107
108 fchmod(fd, 0440);
109 fchown(fd, RunUser, SystemGroupIDs[0]);
110
111 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddCert: NumSystemGroups=%d", NumSystemGroups);
112
113 #ifdef HAVE_ACL_INIT
114 if (NumSystemGroups > 1)
115 {
116 /*
117 * Set POSIX ACLs for the root certificate so that all system
118 * groups can access it...
119 */
120
121 int j; /* Looping var */
122
123 # ifdef HAVE_MBR_UID_TO_UUID
124 /*
125 * On MacOS X, ACLs use UUIDs instead of GIDs...
126 */
127
128 acl = acl_init(NumSystemGroups - 1);
129
130 for (i = 1; i < NumSystemGroups; i ++)
131 {
132 /*
133 * Add each group ID to the ACL...
134 */
135
136 for (j = 0; j < i; j ++)
137 if (SystemGroupIDs[j] == SystemGroupIDs[i])
138 break;
139
140 if (j < i)
141 continue; /* Skip duplicate groups */
142
143 acl_create_entry(&acl, &entry);
144 acl_get_permset(entry, &permset);
145 acl_add_perm(permset, ACL_READ_DATA);
146 acl_set_tag_type(entry, ACL_EXTENDED_ALLOW);
147 mbr_gid_to_uuid((gid_t)SystemGroupIDs[i], group);
148 acl_set_qualifier(entry, &group);
149 acl_set_permset(entry, permset);
150 }
151
152 # else
153 /*
154 * POSIX ACLs need permissions for owner, group, other, and mask
155 * in addition to the rest of the system groups...
156 */
157
158 acl = acl_init(NumSystemGroups + 3);
159
160 /* Owner */
161 acl_create_entry(&acl, &entry);
162 acl_get_permset(entry, &permset);
163 acl_add_perm(permset, ACL_READ);
164 acl_set_tag_type(entry, ACL_USER_OBJ);
165 acl_set_permset(entry, permset);
166
167 /* Group */
168 acl_create_entry(&acl, &entry);
169 acl_get_permset(entry, &permset);
170 acl_add_perm(permset, ACL_READ);
171 acl_set_tag_type(entry, ACL_GROUP_OBJ);
172 acl_set_permset(entry, permset);
173
174 /* Others */
175 acl_create_entry(&acl, &entry);
176 acl_get_permset(entry, &permset);
177 acl_add_perm(permset, 0);
178 acl_set_tag_type(entry, ACL_OTHER);
179 acl_set_permset(entry, permset);
180
181 /* Mask */
182 acl_create_entry(&acl, &entry);
183 acl_get_permset(entry, &permset);
184 acl_add_perm(permset, ACL_READ);
185 acl_set_tag_type(entry, ACL_MASK);
186 acl_set_permset(entry, permset);
187
188 for (i = 1; i < NumSystemGroups; i ++)
189 {
190 /*
191 * Add each group ID to the ACL...
192 */
193
194 for (j = 0; j < i; j ++)
195 if (SystemGroupIDs[j] == SystemGroupIDs[i])
196 break;
197
198 if (j < i)
199 continue; /* Skip duplicate groups */
200
201 acl_create_entry(&acl, &entry);
202 acl_get_permset(entry, &permset);
203 acl_add_perm(permset, ACL_READ);
204 acl_set_tag_type(entry, ACL_GROUP);
205 acl_set_qualifier(entry, SystemGroupIDs + i);
206 acl_set_permset(entry, permset);
207 }
208
209 if (acl_valid(acl))
210 {
211 char *text, *textptr; /* Temporary string */
212
213 cupsdLogMessage(CUPSD_LOG_ERROR, "ACL did not validate: %s",
214 strerror(errno));
215 text = acl_to_text(acl, NULL);
216 for (textptr = strchr(text, '\n');
217 textptr;
218 textptr = strchr(textptr + 1, '\n'))
219 *textptr = ',';
220
221 cupsdLogMessage(CUPSD_LOG_ERROR, "ACL: %s", text);
222 acl_free(text);
223 }
224 # endif /* HAVE_MBR_UID_TO_UUID */
225
226 if (acl_set_fd(fd, acl))
227 {
228 if (errno != EOPNOTSUPP || !acls_not_supported)
229 cupsdLogMessage(CUPSD_LOG_ERROR,
230 "Unable to set ACLs on root certificate \"%s\" - %s",
231 filename, strerror(errno));
232
233 if (errno == EOPNOTSUPP)
234 acls_not_supported = 1;
235 }
236
237 acl_free(acl);
238 }
239 #endif /* HAVE_ACL_INIT */
240
241 RootCertTime = time(NULL);
242 }
243 else
244 {
245 /*
246 * CGI certificate...
247 */
248
249 fchmod(fd, 0400);
250 fchown(fd, User, Group);
251 }
252
253 DEBUG_printf(("ADD pid=%d, username=%s, cert=%s\n", pid, username,
254 cert->certificate));
255
256 write(fd, cert->certificate, strlen(cert->certificate));
257 close(fd);
258
259 /*
260 * Insert the certificate at the front of the list...
261 */
262
263 cert->next = Certs;
264 Certs = cert;
265 }
266
267
268 /*
269 * 'cupsdDeleteCert()' - Delete a single certificate.
270 */
271
272 void
273 cupsdDeleteCert(int pid) /* I - Process ID */
274 {
275 cupsd_cert_t *cert, /* Current certificate */
276 *prev; /* Previous certificate */
277 char filename[1024]; /* Certificate file */
278
279
280 for (prev = NULL, cert = Certs; cert != NULL; prev = cert, cert = cert->next)
281 if (cert->pid == pid)
282 {
283 /*
284 * Remove this certificate from the list...
285 */
286
287 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDeleteCert: Removing certificate for PID %d.", pid);
288
289 DEBUG_printf(("DELETE pid=%d, username=%s, cert=%s\n", cert->pid,
290 cert->username, cert->certificate));
291
292 if (prev == NULL)
293 Certs = cert->next;
294 else
295 prev->next = cert->next;
296
297 free(cert);
298
299 /*
300 * Delete the file and return...
301 */
302
303 snprintf(filename, sizeof(filename), "%s/certs/%d", StateDir, pid);
304 if (unlink(filename))
305 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to remove %s!", filename);
306
307 return;
308 }
309 }
310
311
312 /*
313 * 'cupsdDeleteAllCerts()' - Delete all certificates...
314 */
315
316 void
317 cupsdDeleteAllCerts(void)
318 {
319 cupsd_cert_t *cert, /* Current certificate */
320 *next; /* Next certificate */
321 char filename[1024]; /* Certificate file */
322
323
324 /*
325 * Loop through each certificate, deleting them...
326 */
327
328 for (cert = Certs; cert != NULL; cert = next)
329 {
330 /*
331 * Delete the file...
332 */
333
334 snprintf(filename, sizeof(filename), "%s/certs/%d", StateDir, cert->pid);
335 if (unlink(filename))
336 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to remove %s!", filename);
337
338 /*
339 * Free memory...
340 */
341
342 next = cert->next;
343 free(cert);
344 }
345
346 Certs = NULL;
347 RootCertTime = 0;
348 }
349
350
351 /*
352 * 'cupsdFindCert()' - Find a certificate.
353 */
354
355 cupsd_cert_t * /* O - Matching certificate or NULL */
356 cupsdFindCert(const char *certificate) /* I - Certificate */
357 {
358 cupsd_cert_t *cert; /* Current certificate */
359
360
361 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindCert(certificate=%s)", certificate);
362 for (cert = Certs; cert != NULL; cert = cert->next)
363 if (!ctcompare(certificate, cert->certificate))
364 {
365 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindCert: Returning \"%s\".", cert->username);
366 return (cert);
367 }
368
369 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindCert: Certificate not found.");
370
371 return (NULL);
372 }
373
374
375 /*
376 * 'cupsdInitCerts()' - Initialize the certificate "system" and root
377 * certificate.
378 */
379
380 void
381 cupsdInitCerts(void)
382 {
383 #ifndef HAVE_ARC4RANDOM
384 cups_file_t *fp; /* /dev/random file */
385
386
387 /*
388 * Initialize the random number generator using the random device or
389 * the current time, as available...
390 */
391
392 if ((fp = cupsFileOpen("/dev/urandom", "rb")) == NULL)
393 {
394 struct timeval tod; /* Time of day */
395
396 /*
397 * Get the time in usecs and use it as the initial seed...
398 */
399
400 gettimeofday(&tod, NULL);
401
402 CUPS_SRAND((unsigned)(tod.tv_sec + tod.tv_usec));
403 }
404 else
405 {
406 unsigned seed; /* Seed for random number generator */
407
408 /*
409 * Read 4 random characters from the random device and use
410 * them as the seed...
411 */
412
413 seed = (unsigned)cupsFileGetChar(fp);
414 seed = (seed << 8) | (unsigned)cupsFileGetChar(fp);
415 seed = (seed << 8) | (unsigned)cupsFileGetChar(fp);
416 CUPS_SRAND((seed << 8) | (unsigned)cupsFileGetChar(fp));
417
418 cupsFileClose(fp);
419 }
420 #endif /* !HAVE_ARC4RANDOM */
421
422 /*
423 * Create a root certificate and return...
424 */
425
426 if (!RunUser)
427 cupsdAddCert(0, "root", cupsdDefaultAuthType());
428 }
429
430
431 /*
432 * 'ctcompare()' - Compare two strings in constant time.
433 */
434
435 static int /* O - 0 on match, non-zero on non-match */
436 ctcompare(const char *a, /* I - First string */
437 const char *b) /* I - Second string */
438 {
439 int result = 0; /* Result */
440
441
442 while (*a && *b)
443 result |= *a ^ *b;
444
445 return (result);
446 }
447
448
449 /*
450 * End of "$Id$".
451 */