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