]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/cert.c
Merge changes from CUPS 1.4svn-r7874.
[thirdparty/cups.git] / scheduler / cert.c
1 /*
2 * "$Id: cert.c 7673 2008-06-18 22:31:26Z mike $"
3 *
4 * Authentication certificate routines for the Common UNIX
5 * Printing System (CUPS).
6 *
7 * Copyright 2007-2008 by Apple Inc.
8 * Copyright 1997-2006 by Easy Software Products.
9 *
10 * These coded instructions, statements, and computer programs are the
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/".
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"
31 #ifdef HAVE_ACL_INIT
32 # include <sys/acl.h>
33 # ifdef HAVE_MEMBERSHIP_H
34 # include <membership.h>
35 # endif /* HAVE_MEMBERSHIP_H */
36 #endif /* HAVE_ACL_INIT */
37
38
39 /*
40 * 'cupsdAddCert()' - Add a certificate.
41 */
42
43 void
44 cupsdAddCert(int pid, /* I - Process ID */
45 const char *username, /* I - Username */
46 void *ccache) /* I - Kerberos credentials or NULL */
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,
57 "cupsdAddCert: adding certificate for pid %d", pid);
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 ++)
74 cert->certificate[i] = hex[random() & 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 "cupsdAddCert: 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 # ifdef HAVE_MBR_UID_TO_UUID
126 /*
127 * On MacOS X, ACLs use UUIDs instead of GIDs...
128 */
129
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 }
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);
171 acl_add_perm(permset, 0);
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 {
198 char *text, *textptr; /* Temporary string */
199
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 */
213
214 if (acl_set_fd(fd, acl))
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
225 acl_free(acl);
226 }
227 #endif /* HAVE_ACL_INIT */
228
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
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
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
270 void
271 cupsdDeleteCert(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,
286 "cupsdDeleteCert: removing certificate for pid %d", pid);
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
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
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))
313 cupsdLogMessage(CUPSD_LOG_ERROR,
314 "cupsdDeleteCert: Unable to remove %s!", filename);
315
316 return;
317 }
318 }
319
320
321 /*
322 * 'cupsdDeleteAllCerts()' - Delete all certificates...
323 */
324
325 void
326 cupsdDeleteAllCerts(void)
327 {
328 cupsd_cert_t *cert, /* Current certificate */
329 *next; /* Next certificate */
330 char filename[1024]; /* Certificate file */
331
332
333 /*
334 * Loop through each certificate, deleting them...
335 */
336
337 for (cert = Certs; cert != NULL; cert = next)
338 {
339 /*
340 * Delete the file...
341 */
342
343 snprintf(filename, sizeof(filename), "%s/certs/%d", StateDir, cert->pid);
344 if (unlink(filename))
345 cupsdLogMessage(CUPSD_LOG_ERROR,
346 "cupsdDeleteAllCerts: Unable to remove %s!", filename);
347
348 /*
349 * Free memory...
350 */
351
352 next = cert->next;
353 free(cert);
354 }
355
356 Certs = NULL;
357 RootCertTime = 0;
358 }
359
360
361 /*
362 * 'cupsdFindCert()' - Find a certificate.
363 */
364
365 cupsd_cert_t * /* O - Matching certificate or NULL */
366 cupsdFindCert(const char *certificate) /* I - Certificate */
367 {
368 cupsd_cert_t *cert; /* Current certificate */
369
370
371 DEBUG_printf(("cupsdFindCert(certificate=%s)\n", certificate));
372 for (cert = Certs; cert != NULL; cert = cert->next)
373 if (!strcasecmp(certificate, cert->certificate))
374 {
375 DEBUG_printf((" returning %s...\n", cert->username));
376 return (cert);
377 }
378
379 DEBUG_puts(" certificate not found!");
380
381 return (NULL);
382 }
383
384
385 /*
386 * 'cupsdInitCerts()' - Initialize the certificate "system" and root
387 * certificate.
388 */
389
390 void
391 cupsdInitCerts(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
428 srandom(seed);
429
430 /*
431 * Create a root certificate and return...
432 */
433
434 if (!RunUser)
435 cupsdAddCert(0, "root", NULL);
436 }
437
438
439 /*
440 * End of "$Id: cert.c 7673 2008-06-18 22:31:26Z mike $".
441 */