]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/cert.c
Update svn:keyword properties.
[thirdparty/cups.git] / scheduler / cert.c
CommitLineData
ef416fc2 1/*
f2d18633 2 * "$Id$"
ef416fc2 3 *
10d09e33 4 * Authentication certificate routines for the CUPS scheduler.
ef416fc2 5 *
0fa6c7fa 6 * Copyright 2007-2012 by Apple Inc.
bd7854cb 7 * Copyright 1997-2006 by Easy Software Products.
ef416fc2 8 *
9 * These coded instructions, statements, and computer programs are the
bc44d920 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 * 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"
fa73b229 30#ifdef HAVE_ACL_INIT
31# include <sys/acl.h>
bd7854cb 32# ifdef HAVE_MEMBERSHIP_H
33# include <membership.h>
34# endif /* HAVE_MEMBERSHIP_H */
fa73b229 35#endif /* HAVE_ACL_INIT */
ef416fc2 36
37
38/*
39 * 'cupsdAddCert()' - Add a certificate.
40 */
41
42void
43cupsdAddCert(int pid, /* I - Process ID */
5bd77a73 44 const char *username, /* I - Username */
0fa6c7fa 45 int type) /* I - AuthType for username */
ef416fc2 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,
b9faaae1 56 "cupsdAddCert: Adding certificate for PID %d", pid);
ef416fc2 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
0fa6c7fa
MS
69 cert->pid = pid;
70 cert->type = type;
ef416fc2 71 strlcpy(cert->username, username, sizeof(cert->username));
72
73 for (i = 0; i < 32; i ++)
41681883 74 cert->certificate[i] = hex[CUPS_RAND() & 15];
ef416fc2 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,
b9faaae1 87 "Unable to create certificate file %s - %s",
ef416fc2 88 filename, strerror(errno));
89 free(cert);
90 return;
91 }
92
93 if (pid == 0)
94 {
fa73b229 95#ifdef HAVE_ACL_INIT
96 acl_t acl; /* ACL information */
97 acl_entry_t entry; /* ACL entry */
98 acl_permset_t permset; /* Permissions */
bd7854cb 99# ifdef HAVE_MBR_UID_TO_UUID
fa73b229 100 uuid_t group; /* Group ID */
bd7854cb 101# endif /* HAVE_MBR_UID_TO_UUID */
e53920b9 102 static int acls_not_supported = 0;
103 /* Only warn once */
fa73b229 104#endif /* HAVE_ACL_INIT */
105
106
ef416fc2 107 /*
108 * Root certificate...
109 */
110
111 fchmod(fd, 0440);
112 fchown(fd, RunUser, SystemGroupIDs[0]);
113
bd7854cb 114 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddCert: NumSystemGroups=%d",
115 NumSystemGroups);
116
fa73b229 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
12f89d24
MS
125 int j; /* Looping var */
126
bd7854cb 127# ifdef HAVE_MBR_UID_TO_UUID
128 /*
129 * On MacOS X, ACLs use UUIDs instead of GIDs...
130 */
131
fa73b229 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
12f89d24
MS
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
fa73b229 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 }
12f89d24 155
bd7854cb 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);
4744bd90 181 acl_add_perm(permset, 0);
bd7854cb 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
12f89d24
MS
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
bd7854cb 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 {
e53920b9 215 char *text, *textptr; /* Temporary string */
216
bd7854cb 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);
a2326b5b 226 acl_free(text);
bd7854cb 227 }
228# endif /* HAVE_MBR_UID_TO_UUID */
fa73b229 229
230 if (acl_set_fd(fd, acl))
e53920b9 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
fa73b229 241 acl_free(acl);
242 }
243#endif /* HAVE_ACL_INIT */
244
ef416fc2 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
276void
277cupsdDeleteCert(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,
b9faaae1 292 "cupsdDeleteCert: Removing certificate for PID %d", pid);
ef416fc2 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))
b9faaae1 310 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to remove %s!", filename);
ef416fc2 311
312 return;
313 }
314}
315
316
317/*
318 * 'cupsdDeleteAllCerts()' - Delete all certificates...
319 */
320
321void
322cupsdDeleteAllCerts(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))
b9faaae1 341 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to remove %s!", filename);
ef416fc2 342
343 /*
344 * Free memory...
345 */
346
347 next = cert->next;
348 free(cert);
349 }
350
e1d6a774 351 Certs = NULL;
352 RootCertTime = 0;
ef416fc2 353}
354
355
356/*
357 * 'cupsdFindCert()' - Find a certificate.
358 */
359
db0bd74a 360cupsd_cert_t * /* O - Matching certificate or NULL */
ef416fc2 361cupsdFindCert(const char *certificate) /* I - Certificate */
362{
363 cupsd_cert_t *cert; /* Current certificate */
364
365
b9faaae1
MS
366 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindCert(certificate=%s)",
367 certificate);
ef416fc2 368 for (cert = Certs; cert != NULL; cert = cert->next)
88f9aafc 369 if (!_cups_strcasecmp(certificate, cert->certificate))
ef416fc2 370 {
b9faaae1
MS
371 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindCert: Returning %s...",
372 cert->username);
db0bd74a 373 return (cert);
ef416fc2 374 }
375
b9faaae1 376 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindCert: Certificate not found!");
ef416fc2 377
378 return (NULL);
379}
380
381
382/*
383 * 'cupsdInitCerts()' - Initialize the certificate "system" and root
384 * certificate.
385 */
386
387void
388cupsdInitCerts(void)
389{
f8b3a85b 390#ifndef HAVE_ARC4RANDOM
ef416fc2 391 cups_file_t *fp; /* /dev/random file */
ef416fc2 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 {
f8b3a85b
MS
401 struct timeval tod; /* Time of day */
402
ef416fc2 403 /*
404 * Get the time in usecs and use it as the initial seed...
405 */
406
407 gettimeofday(&tod, NULL);
408
f8b3a85b 409 CUPS_SRAND((unsigned)(tod.tv_sec + tod.tv_usec));
ef416fc2 410 }
411 else
412 {
f8b3a85b
MS
413 unsigned seed; /* Seed for random number generator */
414
ef416fc2 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);
f8b3a85b 423 CUPS_SRAND((seed << 8) | cupsFileGetChar(fp));
ef416fc2 424
425 cupsFileClose(fp);
426 }
f8b3a85b 427#endif /* !HAVE_ARC4RANDOM */
ef416fc2 428
429 /*
430 * Create a root certificate and return...
431 */
432
433 if (!RunUser)
0fa6c7fa 434 cupsdAddCert(0, "root", cupsdDefaultAuthType());
ef416fc2 435}
436
437
438/*
f2d18633 439 * End of "$Id$".
ef416fc2 440 */