]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/cert.c
Load cups into easysw/current.
[thirdparty/cups.git] / scheduler / cert.c
1 /*
2 * "$Id: cert.c 6649 2007-07-11 21:46:42Z mike $"
3 *
4 * Authentication certificate routines for the Common UNIX
5 * Printing System (CUPS).
6 *
7 * Copyright 2007 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 {
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,
56 "cupsdAddCert: adding certificate for pid %d", pid);
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 ++)
73 cert->certificate[i] = hex[random() & 15];
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,
86 "cupsdAddCert: Unable to create certificate file %s - %s",
87 filename, strerror(errno));
88 free(cert);
89 return;
90 }
91
92 if (pid == 0)
93 {
94 #ifdef HAVE_ACL_INIT
95 acl_t acl; /* ACL information */
96 acl_entry_t entry; /* ACL entry */
97 acl_permset_t permset; /* Permissions */
98 # ifdef HAVE_MBR_UID_TO_UUID
99 uuid_t group; /* Group ID */
100 # endif /* HAVE_MBR_UID_TO_UUID */
101 static int acls_not_supported = 0;
102 /* Only warn once */
103 #endif /* HAVE_ACL_INIT */
104
105
106 /*
107 * Root certificate...
108 */
109
110 fchmod(fd, 0440);
111 fchown(fd, RunUser, SystemGroupIDs[0]);
112
113 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddCert: NumSystemGroups=%d",
114 NumSystemGroups);
115
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
124 # ifdef HAVE_MBR_UID_TO_UUID
125 /*
126 * On MacOS X, ACLs use UUIDs instead of GIDs...
127 */
128
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 }
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);
170 acl_add_perm(permset, 0);
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 {
197 char *text, *textptr; /* Temporary string */
198
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);
209 free(text);
210 }
211 # endif /* HAVE_MBR_UID_TO_UUID */
212
213 if (acl_set_fd(fd, acl))
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
224 acl_free(acl);
225 }
226 #endif /* HAVE_ACL_INIT */
227
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
246 /*
247 * Insert the certificate at the front of the list...
248 */
249
250 cert->next = Certs;
251 Certs = cert;
252 }
253
254
255 /*
256 * 'cupsdDeleteCert()' - Delete a single certificate.
257 */
258
259 void
260 cupsdDeleteCert(int pid) /* I - Process ID */
261 {
262 cupsd_cert_t *cert, /* Current certificate */
263 *prev; /* Previous certificate */
264 char filename[1024]; /* Certificate file */
265
266
267 for (prev = NULL, cert = Certs; cert != NULL; prev = cert, cert = cert->next)
268 if (cert->pid == pid)
269 {
270 /*
271 * Remove this certificate from the list...
272 */
273
274 cupsdLogMessage(CUPSD_LOG_DEBUG2,
275 "cupsdDeleteCert: removing certificate for pid %d", pid);
276
277 DEBUG_printf(("DELETE pid=%d, username=%s, cert=%s\n", cert->pid,
278 cert->username, cert->certificate));
279
280 if (prev == NULL)
281 Certs = cert->next;
282 else
283 prev->next = cert->next;
284
285 free(cert);
286
287 /*
288 * Delete the file and return...
289 */
290
291 snprintf(filename, sizeof(filename), "%s/certs/%d", StateDir, pid);
292 if (unlink(filename))
293 cupsdLogMessage(CUPSD_LOG_ERROR,
294 "cupsdDeleteCert: Unable to remove %s!\n", filename);
295
296 return;
297 }
298 }
299
300
301 /*
302 * 'cupsdDeleteAllCerts()' - Delete all certificates...
303 */
304
305 void
306 cupsdDeleteAllCerts(void)
307 {
308 cupsd_cert_t *cert, /* Current certificate */
309 *next; /* Next certificate */
310 char filename[1024]; /* Certificate file */
311
312
313 /*
314 * Loop through each certificate, deleting them...
315 */
316
317 for (cert = Certs; cert != NULL; cert = next)
318 {
319 /*
320 * Delete the file...
321 */
322
323 snprintf(filename, sizeof(filename), "%s/certs/%d", StateDir, cert->pid);
324 if (unlink(filename))
325 cupsdLogMessage(CUPSD_LOG_ERROR,
326 "cupsdDeleteAllCerts: Unable to remove %s!\n", filename);
327
328 /*
329 * Free memory...
330 */
331
332 next = cert->next;
333 free(cert);
334 }
335
336 Certs = NULL;
337 RootCertTime = 0;
338 }
339
340
341 /*
342 * 'cupsdFindCert()' - Find a certificate.
343 */
344
345 const char * /* O - Matching username or NULL */
346 cupsdFindCert(const char *certificate) /* I - Certificate */
347 {
348 cupsd_cert_t *cert; /* Current certificate */
349
350
351 DEBUG_printf(("cupsdFindCert(certificate=%s)\n", certificate));
352 for (cert = Certs; cert != NULL; cert = cert->next)
353 if (!strcasecmp(certificate, cert->certificate))
354 {
355 DEBUG_printf((" returning %s...\n", cert->username));
356 return (cert->username);
357 }
358
359 DEBUG_puts(" certificate not found!");
360
361 return (NULL);
362 }
363
364
365 /*
366 * 'cupsdInitCerts()' - Initialize the certificate "system" and root
367 * certificate.
368 */
369
370 void
371 cupsdInitCerts(void)
372 {
373 cups_file_t *fp; /* /dev/random file */
374 unsigned seed; /* Seed for random number generator */
375 struct timeval tod; /* Time of day */
376
377
378 /*
379 * Initialize the random number generator using the random device or
380 * the current time, as available...
381 */
382
383 if ((fp = cupsFileOpen("/dev/urandom", "rb")) == NULL)
384 {
385 /*
386 * Get the time in usecs and use it as the initial seed...
387 */
388
389 gettimeofday(&tod, NULL);
390
391 seed = (unsigned)(tod.tv_sec + tod.tv_usec);
392 }
393 else
394 {
395 /*
396 * Read 4 random characters from the random device and use
397 * them as the seed...
398 */
399
400 seed = cupsFileGetChar(fp);
401 seed = (seed << 8) | cupsFileGetChar(fp);
402 seed = (seed << 8) | cupsFileGetChar(fp);
403 seed = (seed << 8) | cupsFileGetChar(fp);
404
405 cupsFileClose(fp);
406 }
407
408 srandom(seed);
409
410 /*
411 * Create a root certificate and return...
412 */
413
414 if (!RunUser)
415 cupsdAddCert(0, "root");
416 }
417
418
419 /*
420 * End of "$Id: cert.c 6649 2007-07-11 21:46:42Z mike $".
421 */