]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/cert.c
Remove all of the Subversion keywords from various source files.
[thirdparty/cups.git] / scheduler / cert.c
CommitLineData
ef416fc2 1/*
7e86f2f6 2 * Authentication certificate routines for the CUPS scheduler.
ef416fc2 3 *
1b6c7278 4 * Copyright 2007-2015 by Apple Inc.
7e86f2f6 5 * Copyright 1997-2006 by Easy Software Products.
ef416fc2 6 *
7e86f2f6
MS
7 * These coded instructions, statements, and computer programs are the
8 * property of Apple Inc. and are protected by Federal copyright
9 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
10 * which should have been included with this file. If this file is
11 * file is missing or damaged, see the license at "http://www.cups.org/".
ef416fc2 12 */
13
14/*
15 * Include necessary headers...
16 */
17
18#include "cupsd.h"
fa73b229 19#ifdef HAVE_ACL_INIT
20# include <sys/acl.h>
bd7854cb 21# ifdef HAVE_MEMBERSHIP_H
22# include <membership.h>
23# endif /* HAVE_MEMBERSHIP_H */
fa73b229 24#endif /* HAVE_ACL_INIT */
ef416fc2 25
26
1b6c7278
MS
27/*
28 * Local functions...
29 */
30
31static int ctcompare(const char *a, const char *b);
32
33
ef416fc2 34/*
35 * 'cupsdAddCert()' - Add a certificate.
36 */
37
38void
39cupsdAddCert(int pid, /* I - Process ID */
5bd77a73 40 const char *username, /* I - Username */
0fa6c7fa 41 int type) /* I - AuthType for username */
ef416fc2 42{
43 int i; /* Looping var */
44 cupsd_cert_t *cert; /* Current certificate */
45 int fd; /* Certificate file */
46 char filename[1024]; /* Certificate filename */
47 static const char hex[] = "0123456789ABCDEF";
48 /* Hex constants... */
49
50
6c2b2b19 51 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAddCert: Adding certificate for PID %d", pid);
ef416fc2 52
53 /*
54 * Allocate memory for the certificate...
55 */
56
57 if ((cert = calloc(sizeof(cupsd_cert_t), 1)) == NULL)
58 return;
59
60 /*
61 * Fill in the certificate information...
62 */
63
0fa6c7fa
MS
64 cert->pid = pid;
65 cert->type = type;
ef416fc2 66 strlcpy(cert->username, username, sizeof(cert->username));
67
68 for (i = 0; i < 32; i ++)
41681883 69 cert->certificate[i] = hex[CUPS_RAND() & 15];
ef416fc2 70
71 /*
72 * Save the certificate to a file readable only by the User and Group
73 * (or root and SystemGroup for PID == 0)...
74 */
75
76 snprintf(filename, sizeof(filename), "%s/certs/%d", StateDir, pid);
77 unlink(filename);
78
79 if ((fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0400)) < 0)
80 {
81 cupsdLogMessage(CUPSD_LOG_ERROR,
b9faaae1 82 "Unable to create certificate file %s - %s",
ef416fc2 83 filename, strerror(errno));
84 free(cert);
85 return;
86 }
87
88 if (pid == 0)
89 {
fa73b229 90#ifdef HAVE_ACL_INIT
91 acl_t acl; /* ACL information */
92 acl_entry_t entry; /* ACL entry */
93 acl_permset_t permset; /* Permissions */
bd7854cb 94# ifdef HAVE_MBR_UID_TO_UUID
fa73b229 95 uuid_t group; /* Group ID */
bd7854cb 96# endif /* HAVE_MBR_UID_TO_UUID */
e53920b9 97 static int acls_not_supported = 0;
98 /* Only warn once */
fa73b229 99#endif /* HAVE_ACL_INIT */
100
101
ef416fc2 102 /*
103 * Root certificate...
104 */
105
106 fchmod(fd, 0440);
107 fchown(fd, RunUser, SystemGroupIDs[0]);
108
ffe32673 109 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddCert: NumSystemGroups=%d", NumSystemGroups);
bd7854cb 110
fa73b229 111#ifdef HAVE_ACL_INIT
112 if (NumSystemGroups > 1)
113 {
114 /*
115 * Set POSIX ACLs for the root certificate so that all system
116 * groups can access it...
117 */
118
12f89d24
MS
119 int j; /* Looping var */
120
bd7854cb 121# ifdef HAVE_MBR_UID_TO_UUID
122 /*
123 * On MacOS X, ACLs use UUIDs instead of GIDs...
124 */
125
fa73b229 126 acl = acl_init(NumSystemGroups - 1);
127
128 for (i = 1; i < NumSystemGroups; i ++)
129 {
130 /*
131 * Add each group ID to the ACL...
132 */
133
12f89d24
MS
134 for (j = 0; j < i; j ++)
135 if (SystemGroupIDs[j] == SystemGroupIDs[i])
136 break;
137
138 if (j < i)
139 continue; /* Skip duplicate groups */
140
fa73b229 141 acl_create_entry(&acl, &entry);
142 acl_get_permset(entry, &permset);
143 acl_add_perm(permset, ACL_READ_DATA);
144 acl_set_tag_type(entry, ACL_EXTENDED_ALLOW);
145 mbr_gid_to_uuid((gid_t)SystemGroupIDs[i], group);
146 acl_set_qualifier(entry, &group);
147 acl_set_permset(entry, permset);
148 }
12f89d24 149
bd7854cb 150# else
151 /*
152 * POSIX ACLs need permissions for owner, group, other, and mask
153 * in addition to the rest of the system groups...
154 */
155
156 acl = acl_init(NumSystemGroups + 3);
157
158 /* Owner */
159 acl_create_entry(&acl, &entry);
160 acl_get_permset(entry, &permset);
161 acl_add_perm(permset, ACL_READ);
162 acl_set_tag_type(entry, ACL_USER_OBJ);
163 acl_set_permset(entry, permset);
164
165 /* Group */
166 acl_create_entry(&acl, &entry);
167 acl_get_permset(entry, &permset);
168 acl_add_perm(permset, ACL_READ);
169 acl_set_tag_type(entry, ACL_GROUP_OBJ);
170 acl_set_permset(entry, permset);
171
172 /* Others */
173 acl_create_entry(&acl, &entry);
174 acl_get_permset(entry, &permset);
4744bd90 175 acl_add_perm(permset, 0);
bd7854cb 176 acl_set_tag_type(entry, ACL_OTHER);
177 acl_set_permset(entry, permset);
178
179 /* Mask */
180 acl_create_entry(&acl, &entry);
181 acl_get_permset(entry, &permset);
182 acl_add_perm(permset, ACL_READ);
183 acl_set_tag_type(entry, ACL_MASK);
184 acl_set_permset(entry, permset);
185
186 for (i = 1; i < NumSystemGroups; i ++)
187 {
188 /*
189 * Add each group ID to the ACL...
190 */
191
12f89d24
MS
192 for (j = 0; j < i; j ++)
193 if (SystemGroupIDs[j] == SystemGroupIDs[i])
194 break;
195
196 if (j < i)
197 continue; /* Skip duplicate groups */
198
bd7854cb 199 acl_create_entry(&acl, &entry);
200 acl_get_permset(entry, &permset);
201 acl_add_perm(permset, ACL_READ);
202 acl_set_tag_type(entry, ACL_GROUP);
203 acl_set_qualifier(entry, SystemGroupIDs + i);
204 acl_set_permset(entry, permset);
205 }
206
207 if (acl_valid(acl))
208 {
e53920b9 209 char *text, *textptr; /* Temporary string */
210
bd7854cb 211 cupsdLogMessage(CUPSD_LOG_ERROR, "ACL did not validate: %s",
212 strerror(errno));
213 text = acl_to_text(acl, NULL);
214 for (textptr = strchr(text, '\n');
215 textptr;
216 textptr = strchr(textptr + 1, '\n'))
217 *textptr = ',';
218
219 cupsdLogMessage(CUPSD_LOG_ERROR, "ACL: %s", text);
a2326b5b 220 acl_free(text);
bd7854cb 221 }
222# endif /* HAVE_MBR_UID_TO_UUID */
fa73b229 223
224 if (acl_set_fd(fd, acl))
e53920b9 225 {
226 if (errno != EOPNOTSUPP || !acls_not_supported)
227 cupsdLogMessage(CUPSD_LOG_ERROR,
228 "Unable to set ACLs on root certificate \"%s\" - %s",
229 filename, strerror(errno));
230
231 if (errno == EOPNOTSUPP)
232 acls_not_supported = 1;
233 }
234
fa73b229 235 acl_free(acl);
236 }
237#endif /* HAVE_ACL_INIT */
238
ef416fc2 239 RootCertTime = time(NULL);
240 }
241 else
242 {
243 /*
244 * CGI certificate...
245 */
246
247 fchmod(fd, 0400);
248 fchown(fd, User, Group);
249 }
250
251 DEBUG_printf(("ADD pid=%d, username=%s, cert=%s\n", pid, username,
252 cert->certificate));
253
254 write(fd, cert->certificate, strlen(cert->certificate));
255 close(fd);
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
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
ffe32673 285 cupsdLogMessage(CUPSD_LOG_DEBUG2, "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
295 free(cert);
296
297 /*
298 * Delete the file and return...
299 */
300
301 snprintf(filename, sizeof(filename), "%s/certs/%d", StateDir, pid);
302 if (unlink(filename))
b9faaae1 303 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to remove %s!", filename);
ef416fc2 304
305 return;
306 }
307}
308
309
310/*
311 * 'cupsdDeleteAllCerts()' - Delete all certificates...
312 */
313
314void
315cupsdDeleteAllCerts(void)
316{
317 cupsd_cert_t *cert, /* Current certificate */
318 *next; /* Next certificate */
319 char filename[1024]; /* Certificate file */
320
321
322 /*
323 * Loop through each certificate, deleting them...
324 */
325
326 for (cert = Certs; cert != NULL; cert = next)
327 {
328 /*
329 * Delete the file...
330 */
331
332 snprintf(filename, sizeof(filename), "%s/certs/%d", StateDir, cert->pid);
333 if (unlink(filename))
b9faaae1 334 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to remove %s!", filename);
ef416fc2 335
336 /*
337 * Free memory...
338 */
339
340 next = cert->next;
341 free(cert);
342 }
343
e1d6a774 344 Certs = NULL;
345 RootCertTime = 0;
ef416fc2 346}
347
348
349/*
350 * 'cupsdFindCert()' - Find a certificate.
351 */
352
db0bd74a 353cupsd_cert_t * /* O - Matching certificate or NULL */
ef416fc2 354cupsdFindCert(const char *certificate) /* I - Certificate */
355{
356 cupsd_cert_t *cert; /* Current certificate */
357
358
ffe32673 359 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindCert(certificate=%s)", certificate);
ef416fc2 360 for (cert = Certs; cert != NULL; cert = cert->next)
1b6c7278 361 if (!ctcompare(certificate, cert->certificate))
ef416fc2 362 {
ffe32673 363 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindCert: Returning \"%s\".", cert->username);
db0bd74a 364 return (cert);
ef416fc2 365 }
366
ffe32673 367 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindCert: Certificate not found.");
ef416fc2 368
369 return (NULL);
370}
371
372
373/*
374 * 'cupsdInitCerts()' - Initialize the certificate "system" and root
375 * certificate.
376 */
377
378void
379cupsdInitCerts(void)
380{
f8b3a85b 381#ifndef HAVE_ARC4RANDOM
ef416fc2 382 cups_file_t *fp; /* /dev/random file */
ef416fc2 383
384
385 /*
386 * Initialize the random number generator using the random device or
387 * the current time, as available...
388 */
389
390 if ((fp = cupsFileOpen("/dev/urandom", "rb")) == NULL)
391 {
f8b3a85b
MS
392 struct timeval tod; /* Time of day */
393
ef416fc2 394 /*
395 * Get the time in usecs and use it as the initial seed...
396 */
397
398 gettimeofday(&tod, NULL);
399
f8b3a85b 400 CUPS_SRAND((unsigned)(tod.tv_sec + tod.tv_usec));
ef416fc2 401 }
402 else
403 {
f8b3a85b
MS
404 unsigned seed; /* Seed for random number generator */
405
ef416fc2 406 /*
407 * Read 4 random characters from the random device and use
408 * them as the seed...
409 */
410
07623986
MS
411 seed = (unsigned)cupsFileGetChar(fp);
412 seed = (seed << 8) | (unsigned)cupsFileGetChar(fp);
413 seed = (seed << 8) | (unsigned)cupsFileGetChar(fp);
414 CUPS_SRAND((seed << 8) | (unsigned)cupsFileGetChar(fp));
ef416fc2 415
416 cupsFileClose(fp);
417 }
f8b3a85b 418#endif /* !HAVE_ARC4RANDOM */
ef416fc2 419
420 /*
421 * Create a root certificate and return...
422 */
423
424 if (!RunUser)
0fa6c7fa 425 cupsdAddCert(0, "root", cupsdDefaultAuthType());
ef416fc2 426}
427
428
1b6c7278
MS
429/*
430 * 'ctcompare()' - Compare two strings in constant time.
431 */
432
433static int /* O - 0 on match, non-zero on non-match */
434ctcompare(const char *a, /* I - First string */
435 const char *b) /* I - Second string */
436{
437 int result = 0; /* Result */
438
439
440 while (*a && *b)
c1bc6894 441 {
1b6c7278 442 result |= *a ^ *b;
c1bc6894
MS
443 a ++;
444 b ++;
445 }
1b6c7278
MS
446
447 return (result);
448}