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