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