]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/cert.c
Merge changes from CUPS 1.5svn-r8950.
[thirdparty/cups.git] / scheduler / cert.c
CommitLineData
ef416fc2 1/*
75bd9771 2 * "$Id: cert.c 7673 2008-06-18 22:31:26Z mike $"
ef416fc2 3 *
4 * Authentication certificate routines for the Common UNIX
5 * Printing System (CUPS).
6 *
b9faaae1 7 * Copyright 2007-2009 by Apple Inc.
bd7854cb 8 * Copyright 1997-2006 by Easy Software Products.
ef416fc2 9 *
10 * These coded instructions, statements, and computer programs are the
bc44d920 11 * property of Apple Inc. and are protected by Federal copyright
12 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
13 * which should have been included with this file. If this file is
14 * file is missing or damaged, see the license at "http://www.cups.org/".
ef416fc2 15 *
16 * Contents:
17 *
18 * cupsdAddCert() - Add a certificate.
19 * cupsdDeleteCert() - Delete a single certificate.
20 * cupsdDeleteAllCerts() - Delete all certificates...
21 * cupsdFindCert() - Find a certificate.
22 * cupsdInitCerts() - Initialize the certificate "system" and root
23 * certificate.
24 */
25
26/*
27 * Include necessary headers...
28 */
29
30#include "cupsd.h"
fa73b229 31#ifdef HAVE_ACL_INIT
32# include <sys/acl.h>
bd7854cb 33# ifdef HAVE_MEMBERSHIP_H
34# include <membership.h>
35# endif /* HAVE_MEMBERSHIP_H */
fa73b229 36#endif /* HAVE_ACL_INIT */
ef416fc2 37
38
39/*
40 * 'cupsdAddCert()' - Add a certificate.
41 */
42
43void
44cupsdAddCert(int pid, /* I - Process ID */
5bd77a73
MS
45 const char *username, /* I - Username */
46 void *ccache) /* I - Kerberos credentials or NULL */
ef416fc2 47{
48 int i; /* Looping var */
49 cupsd_cert_t *cert; /* Current certificate */
50 int fd; /* Certificate file */
51 char filename[1024]; /* Certificate filename */
52 static const char hex[] = "0123456789ABCDEF";
53 /* Hex constants... */
54
55
56 cupsdLogMessage(CUPSD_LOG_DEBUG2,
b9faaae1 57 "cupsdAddCert: Adding certificate for PID %d", pid);
ef416fc2 58
59 /*
60 * Allocate memory for the certificate...
61 */
62
63 if ((cert = calloc(sizeof(cupsd_cert_t), 1)) == NULL)
64 return;
65
66 /*
67 * Fill in the certificate information...
68 */
69
70 cert->pid = pid;
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
bd7854cb 125# ifdef HAVE_MBR_UID_TO_UUID
126 /*
127 * On MacOS X, ACLs use UUIDs instead of GIDs...
128 */
129
fa73b229 130 acl = acl_init(NumSystemGroups - 1);
131
132 for (i = 1; i < NumSystemGroups; i ++)
133 {
134 /*
135 * Add each group ID to the ACL...
136 */
137
138 acl_create_entry(&acl, &entry);
139 acl_get_permset(entry, &permset);
140 acl_add_perm(permset, ACL_READ_DATA);
141 acl_set_tag_type(entry, ACL_EXTENDED_ALLOW);
142 mbr_gid_to_uuid((gid_t)SystemGroupIDs[i], group);
143 acl_set_qualifier(entry, &group);
144 acl_set_permset(entry, permset);
145 }
bd7854cb 146# else
147 /*
148 * POSIX ACLs need permissions for owner, group, other, and mask
149 * in addition to the rest of the system groups...
150 */
151
152 acl = acl_init(NumSystemGroups + 3);
153
154 /* Owner */
155 acl_create_entry(&acl, &entry);
156 acl_get_permset(entry, &permset);
157 acl_add_perm(permset, ACL_READ);
158 acl_set_tag_type(entry, ACL_USER_OBJ);
159 acl_set_permset(entry, permset);
160
161 /* Group */
162 acl_create_entry(&acl, &entry);
163 acl_get_permset(entry, &permset);
164 acl_add_perm(permset, ACL_READ);
165 acl_set_tag_type(entry, ACL_GROUP_OBJ);
166 acl_set_permset(entry, permset);
167
168 /* Others */
169 acl_create_entry(&acl, &entry);
170 acl_get_permset(entry, &permset);
4744bd90 171 acl_add_perm(permset, 0);
bd7854cb 172 acl_set_tag_type(entry, ACL_OTHER);
173 acl_set_permset(entry, permset);
174
175 /* Mask */
176 acl_create_entry(&acl, &entry);
177 acl_get_permset(entry, &permset);
178 acl_add_perm(permset, ACL_READ);
179 acl_set_tag_type(entry, ACL_MASK);
180 acl_set_permset(entry, permset);
181
182 for (i = 1; i < NumSystemGroups; i ++)
183 {
184 /*
185 * Add each group ID to the ACL...
186 */
187
188 acl_create_entry(&acl, &entry);
189 acl_get_permset(entry, &permset);
190 acl_add_perm(permset, ACL_READ);
191 acl_set_tag_type(entry, ACL_GROUP);
192 acl_set_qualifier(entry, SystemGroupIDs + i);
193 acl_set_permset(entry, permset);
194 }
195
196 if (acl_valid(acl))
197 {
e53920b9 198 char *text, *textptr; /* Temporary string */
199
bd7854cb 200
201 cupsdLogMessage(CUPSD_LOG_ERROR, "ACL did not validate: %s",
202 strerror(errno));
203 text = acl_to_text(acl, NULL);
204 for (textptr = strchr(text, '\n');
205 textptr;
206 textptr = strchr(textptr + 1, '\n'))
207 *textptr = ',';
208
209 cupsdLogMessage(CUPSD_LOG_ERROR, "ACL: %s", text);
210 free(text);
211 }
212# endif /* HAVE_MBR_UID_TO_UUID */
fa73b229 213
214 if (acl_set_fd(fd, acl))
e53920b9 215 {
216 if (errno != EOPNOTSUPP || !acls_not_supported)
217 cupsdLogMessage(CUPSD_LOG_ERROR,
218 "Unable to set ACLs on root certificate \"%s\" - %s",
219 filename, strerror(errno));
220
221 if (errno == EOPNOTSUPP)
222 acls_not_supported = 1;
223 }
224
fa73b229 225 acl_free(acl);
226 }
227#endif /* HAVE_ACL_INIT */
228
ef416fc2 229 RootCertTime = time(NULL);
230 }
231 else
232 {
233 /*
234 * CGI certificate...
235 */
236
237 fchmod(fd, 0400);
238 fchown(fd, User, Group);
239 }
240
241 DEBUG_printf(("ADD pid=%d, username=%s, cert=%s\n", pid, username,
242 cert->certificate));
243
244 write(fd, cert->certificate, strlen(cert->certificate));
245 close(fd);
246
5bd77a73
MS
247 /*
248 * Add Kerberos credentials as needed...
249 */
250
251#ifdef HAVE_GSSAPI
252 cert->ccache = (krb5_ccache)ccache;
253#else
254 (void)ccache;
255#endif /* HAVE_GSSAPI */
256
ef416fc2 257 /*
258 * Insert the certificate at the front of the list...
259 */
260
261 cert->next = Certs;
262 Certs = cert;
263}
264
265
266/*
267 * 'cupsdDeleteCert()' - Delete a single certificate.
268 */
269
270void
271cupsdDeleteCert(int pid) /* I - Process ID */
272{
273 cupsd_cert_t *cert, /* Current certificate */
274 *prev; /* Previous certificate */
275 char filename[1024]; /* Certificate file */
276
277
278 for (prev = NULL, cert = Certs; cert != NULL; prev = cert, cert = cert->next)
279 if (cert->pid == pid)
280 {
281 /*
282 * Remove this certificate from the list...
283 */
284
285 cupsdLogMessage(CUPSD_LOG_DEBUG2,
b9faaae1 286 "cupsdDeleteCert: Removing certificate for PID %d", pid);
ef416fc2 287
288 DEBUG_printf(("DELETE pid=%d, username=%s, cert=%s\n", cert->pid,
289 cert->username, cert->certificate));
290
291 if (prev == NULL)
292 Certs = cert->next;
293 else
294 prev->next = cert->next;
295
5bd77a73
MS
296#ifdef HAVE_GSSAPI
297 /*
298 * Release Kerberos credentials as needed...
299 */
300
301 if (cert->ccache)
302 krb5_cc_destroy(KerberosContext, cert->ccache);
303#endif /* HAVE_GSSAPI */
304
ef416fc2 305 free(cert);
306
307 /*
308 * Delete the file and return...
309 */
310
311 snprintf(filename, sizeof(filename), "%s/certs/%d", StateDir, pid);
312 if (unlink(filename))
b9faaae1 313 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to remove %s!", filename);
ef416fc2 314
315 return;
316 }
317}
318
319
320/*
321 * 'cupsdDeleteAllCerts()' - Delete all certificates...
322 */
323
324void
325cupsdDeleteAllCerts(void)
326{
327 cupsd_cert_t *cert, /* Current certificate */
328 *next; /* Next certificate */
329 char filename[1024]; /* Certificate file */
330
331
332 /*
333 * Loop through each certificate, deleting them...
334 */
335
336 for (cert = Certs; cert != NULL; cert = next)
337 {
338 /*
339 * Delete the file...
340 */
341
342 snprintf(filename, sizeof(filename), "%s/certs/%d", StateDir, cert->pid);
343 if (unlink(filename))
b9faaae1 344 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to remove %s!", filename);
ef416fc2 345
346 /*
347 * Free memory...
348 */
349
350 next = cert->next;
351 free(cert);
352 }
353
e1d6a774 354 Certs = NULL;
355 RootCertTime = 0;
ef416fc2 356}
357
358
359/*
360 * 'cupsdFindCert()' - Find a certificate.
361 */
362
db0bd74a 363cupsd_cert_t * /* O - Matching certificate or NULL */
ef416fc2 364cupsdFindCert(const char *certificate) /* I - Certificate */
365{
366 cupsd_cert_t *cert; /* Current certificate */
367
368
b9faaae1
MS
369 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindCert(certificate=%s)",
370 certificate);
ef416fc2 371 for (cert = Certs; cert != NULL; cert = cert->next)
372 if (!strcasecmp(certificate, cert->certificate))
373 {
b9faaae1
MS
374 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindCert: Returning %s...",
375 cert->username);
db0bd74a 376 return (cert);
ef416fc2 377 }
378
b9faaae1 379 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindCert: Certificate not found!");
ef416fc2 380
381 return (NULL);
382}
383
384
385/*
386 * 'cupsdInitCerts()' - Initialize the certificate "system" and root
387 * certificate.
388 */
389
390void
391cupsdInitCerts(void)
392{
393 cups_file_t *fp; /* /dev/random file */
394 unsigned seed; /* Seed for random number generator */
395 struct timeval tod; /* Time of day */
396
397
398 /*
399 * Initialize the random number generator using the random device or
400 * the current time, as available...
401 */
402
403 if ((fp = cupsFileOpen("/dev/urandom", "rb")) == NULL)
404 {
405 /*
406 * Get the time in usecs and use it as the initial seed...
407 */
408
409 gettimeofday(&tod, NULL);
410
411 seed = (unsigned)(tod.tv_sec + tod.tv_usec);
412 }
413 else
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 seed = (seed << 8) | cupsFileGetChar(fp);
424
425 cupsFileClose(fp);
426 }
427
41681883 428 CUPS_SRAND(seed);
ef416fc2 429
430 /*
431 * Create a root certificate and return...
432 */
433
434 if (!RunUser)
5bd77a73 435 cupsdAddCert(0, "root", NULL);
ef416fc2 436}
437
438
439/*
75bd9771 440 * End of "$Id: cert.c 7673 2008-06-18 22:31:26Z mike $".
ef416fc2 441 */