]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/cert.c
Fix build errors on Fedora.
[thirdparty/cups.git] / scheduler / cert.c
CommitLineData
ef416fc2 1/*
f2d18633 2 * "$Id$"
ef416fc2 3 *
7e86f2f6 4 * Authentication certificate routines for the CUPS scheduler.
ef416fc2 5 *
7e86f2f6
MS
6 * Copyright 2007-2014 by Apple Inc.
7 * Copyright 1997-2006 by Easy Software Products.
ef416fc2 8 *
7e86f2f6
MS
9 * These coded instructions, statements, and computer programs are the
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
16/*
17 * Include necessary headers...
18 */
19
20#include "cupsd.h"
fa73b229 21#ifdef HAVE_ACL_INIT
22# include <sys/acl.h>
bd7854cb 23# ifdef HAVE_MEMBERSHIP_H
24# include <membership.h>
25# endif /* HAVE_MEMBERSHIP_H */
fa73b229 26#endif /* HAVE_ACL_INIT */
ef416fc2 27
28
29/*
30 * 'cupsdAddCert()' - Add a certificate.
31 */
32
33void
34cupsdAddCert(int pid, /* I - Process ID */
5bd77a73 35 const char *username, /* I - Username */
0fa6c7fa 36 int type) /* I - AuthType for username */
ef416fc2 37{
38 int i; /* Looping var */
39 cupsd_cert_t *cert; /* Current certificate */
40 int fd; /* Certificate file */
41 char filename[1024]; /* Certificate filename */
42 static const char hex[] = "0123456789ABCDEF";
43 /* Hex constants... */
44
45
46 cupsdLogMessage(CUPSD_LOG_DEBUG2,
b9faaae1 47 "cupsdAddCert: Adding certificate for PID %d", pid);
ef416fc2 48
49 /*
50 * Allocate memory for the certificate...
51 */
52
53 if ((cert = calloc(sizeof(cupsd_cert_t), 1)) == NULL)
54 return;
55
56 /*
57 * Fill in the certificate information...
58 */
59
0fa6c7fa
MS
60 cert->pid = pid;
61 cert->type = type;
ef416fc2 62 strlcpy(cert->username, username, sizeof(cert->username));
63
64 for (i = 0; i < 32; i ++)
41681883 65 cert->certificate[i] = hex[CUPS_RAND() & 15];
ef416fc2 66
67 /*
68 * Save the certificate to a file readable only by the User and Group
69 * (or root and SystemGroup for PID == 0)...
70 */
71
72 snprintf(filename, sizeof(filename), "%s/certs/%d", StateDir, pid);
73 unlink(filename);
74
75 if ((fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0400)) < 0)
76 {
77 cupsdLogMessage(CUPSD_LOG_ERROR,
b9faaae1 78 "Unable to create certificate file %s - %s",
ef416fc2 79 filename, strerror(errno));
80 free(cert);
81 return;
82 }
83
84 if (pid == 0)
85 {
fa73b229 86#ifdef HAVE_ACL_INIT
87 acl_t acl; /* ACL information */
88 acl_entry_t entry; /* ACL entry */
89 acl_permset_t permset; /* Permissions */
bd7854cb 90# ifdef HAVE_MBR_UID_TO_UUID
fa73b229 91 uuid_t group; /* Group ID */
bd7854cb 92# endif /* HAVE_MBR_UID_TO_UUID */
e53920b9 93 static int acls_not_supported = 0;
94 /* Only warn once */
fa73b229 95#endif /* HAVE_ACL_INIT */
96
97
ef416fc2 98 /*
99 * Root certificate...
100 */
101
102 fchmod(fd, 0440);
103 fchown(fd, RunUser, SystemGroupIDs[0]);
104
bd7854cb 105 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddCert: NumSystemGroups=%d",
106 NumSystemGroups);
107
fa73b229 108#ifdef HAVE_ACL_INIT
109 if (NumSystemGroups > 1)
110 {
111 /*
112 * Set POSIX ACLs for the root certificate so that all system
113 * groups can access it...
114 */
115
12f89d24
MS
116 int j; /* Looping var */
117
bd7854cb 118# ifdef HAVE_MBR_UID_TO_UUID
119 /*
120 * On MacOS X, ACLs use UUIDs instead of GIDs...
121 */
122
fa73b229 123 acl = acl_init(NumSystemGroups - 1);
124
125 for (i = 1; i < NumSystemGroups; i ++)
126 {
127 /*
128 * Add each group ID to the ACL...
129 */
130
12f89d24
MS
131 for (j = 0; j < i; j ++)
132 if (SystemGroupIDs[j] == SystemGroupIDs[i])
133 break;
134
135 if (j < i)
136 continue; /* Skip duplicate groups */
137
fa73b229 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 }
12f89d24 146
bd7854cb 147# else
148 /*
149 * POSIX ACLs need permissions for owner, group, other, and mask
150 * in addition to the rest of the system groups...
151 */
152
153 acl = acl_init(NumSystemGroups + 3);
154
155 /* Owner */
156 acl_create_entry(&acl, &entry);
157 acl_get_permset(entry, &permset);
158 acl_add_perm(permset, ACL_READ);
159 acl_set_tag_type(entry, ACL_USER_OBJ);
160 acl_set_permset(entry, permset);
161
162 /* Group */
163 acl_create_entry(&acl, &entry);
164 acl_get_permset(entry, &permset);
165 acl_add_perm(permset, ACL_READ);
166 acl_set_tag_type(entry, ACL_GROUP_OBJ);
167 acl_set_permset(entry, permset);
168
169 /* Others */
170 acl_create_entry(&acl, &entry);
171 acl_get_permset(entry, &permset);
4744bd90 172 acl_add_perm(permset, 0);
bd7854cb 173 acl_set_tag_type(entry, ACL_OTHER);
174 acl_set_permset(entry, permset);
175
176 /* Mask */
177 acl_create_entry(&acl, &entry);
178 acl_get_permset(entry, &permset);
179 acl_add_perm(permset, ACL_READ);
180 acl_set_tag_type(entry, ACL_MASK);
181 acl_set_permset(entry, permset);
182
183 for (i = 1; i < NumSystemGroups; i ++)
184 {
185 /*
186 * Add each group ID to the ACL...
187 */
188
12f89d24
MS
189 for (j = 0; j < i; j ++)
190 if (SystemGroupIDs[j] == SystemGroupIDs[i])
191 break;
192
193 if (j < i)
194 continue; /* Skip duplicate groups */
195
bd7854cb 196 acl_create_entry(&acl, &entry);
197 acl_get_permset(entry, &permset);
198 acl_add_perm(permset, ACL_READ);
199 acl_set_tag_type(entry, ACL_GROUP);
200 acl_set_qualifier(entry, SystemGroupIDs + i);
201 acl_set_permset(entry, permset);
202 }
203
204 if (acl_valid(acl))
205 {
e53920b9 206 char *text, *textptr; /* Temporary string */
207
bd7854cb 208 cupsdLogMessage(CUPSD_LOG_ERROR, "ACL did not validate: %s",
209 strerror(errno));
210 text = acl_to_text(acl, NULL);
211 for (textptr = strchr(text, '\n');
212 textptr;
213 textptr = strchr(textptr + 1, '\n'))
214 *textptr = ',';
215
216 cupsdLogMessage(CUPSD_LOG_ERROR, "ACL: %s", text);
a2326b5b 217 acl_free(text);
bd7854cb 218 }
219# endif /* HAVE_MBR_UID_TO_UUID */
fa73b229 220
221 if (acl_set_fd(fd, acl))
e53920b9 222 {
223 if (errno != EOPNOTSUPP || !acls_not_supported)
224 cupsdLogMessage(CUPSD_LOG_ERROR,
225 "Unable to set ACLs on root certificate \"%s\" - %s",
226 filename, strerror(errno));
227
228 if (errno == EOPNOTSUPP)
229 acls_not_supported = 1;
230 }
231
fa73b229 232 acl_free(acl);
233 }
234#endif /* HAVE_ACL_INIT */
235
ef416fc2 236 RootCertTime = time(NULL);
237 }
238 else
239 {
240 /*
241 * CGI certificate...
242 */
243
244 fchmod(fd, 0400);
245 fchown(fd, User, Group);
246 }
247
248 DEBUG_printf(("ADD pid=%d, username=%s, cert=%s\n", pid, username,
249 cert->certificate));
250
251 write(fd, cert->certificate, strlen(cert->certificate));
252 close(fd);
253
254 /*
255 * Insert the certificate at the front of the list...
256 */
257
258 cert->next = Certs;
259 Certs = cert;
260}
261
262
263/*
264 * 'cupsdDeleteCert()' - Delete a single certificate.
265 */
266
267void
268cupsdDeleteCert(int pid) /* I - Process ID */
269{
270 cupsd_cert_t *cert, /* Current certificate */
271 *prev; /* Previous certificate */
272 char filename[1024]; /* Certificate file */
273
274
275 for (prev = NULL, cert = Certs; cert != NULL; prev = cert, cert = cert->next)
276 if (cert->pid == pid)
277 {
278 /*
279 * Remove this certificate from the list...
280 */
281
282 cupsdLogMessage(CUPSD_LOG_DEBUG2,
b9faaae1 283 "cupsdDeleteCert: Removing certificate for PID %d", pid);
ef416fc2 284
285 DEBUG_printf(("DELETE pid=%d, username=%s, cert=%s\n", cert->pid,
286 cert->username, cert->certificate));
287
288 if (prev == NULL)
289 Certs = cert->next;
290 else
291 prev->next = cert->next;
292
293 free(cert);
294
295 /*
296 * Delete the file and return...
297 */
298
299 snprintf(filename, sizeof(filename), "%s/certs/%d", StateDir, pid);
300 if (unlink(filename))
b9faaae1 301 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to remove %s!", filename);
ef416fc2 302
303 return;
304 }
305}
306
307
308/*
309 * 'cupsdDeleteAllCerts()' - Delete all certificates...
310 */
311
312void
313cupsdDeleteAllCerts(void)
314{
315 cupsd_cert_t *cert, /* Current certificate */
316 *next; /* Next certificate */
317 char filename[1024]; /* Certificate file */
318
319
320 /*
321 * Loop through each certificate, deleting them...
322 */
323
324 for (cert = Certs; cert != NULL; cert = next)
325 {
326 /*
327 * Delete the file...
328 */
329
330 snprintf(filename, sizeof(filename), "%s/certs/%d", StateDir, cert->pid);
331 if (unlink(filename))
b9faaae1 332 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to remove %s!", filename);
ef416fc2 333
334 /*
335 * Free memory...
336 */
337
338 next = cert->next;
339 free(cert);
340 }
341
e1d6a774 342 Certs = NULL;
343 RootCertTime = 0;
ef416fc2 344}
345
346
347/*
348 * 'cupsdFindCert()' - Find a certificate.
349 */
350
db0bd74a 351cupsd_cert_t * /* O - Matching certificate or NULL */
ef416fc2 352cupsdFindCert(const char *certificate) /* I - Certificate */
353{
354 cupsd_cert_t *cert; /* Current certificate */
355
356
b9faaae1
MS
357 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindCert(certificate=%s)",
358 certificate);
ef416fc2 359 for (cert = Certs; cert != NULL; cert = cert->next)
88f9aafc 360 if (!_cups_strcasecmp(certificate, cert->certificate))
ef416fc2 361 {
b9faaae1
MS
362 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindCert: Returning %s...",
363 cert->username);
db0bd74a 364 return (cert);
ef416fc2 365 }
366
b9faaae1 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
429/*
f2d18633 430 * End of "$Id$".
ef416fc2 431 */