]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/cert.c
Import CUPS v2.0b1
[thirdparty/cups.git] / scheduler / cert.c
CommitLineData
ef416fc2 1/*
1a18c85c 2 * "$Id: cert.c 12034 2014-07-16 19:37:34Z msweet $"
ef416fc2 3 *
1a18c85c 4 * Authentication certificate routines for the CUPS scheduler.
ef416fc2 5 *
1a18c85c
MS
6 * Copyright 2007-2014 by Apple Inc.
7 * Copyright 1997-2006 by Easy Software Products.
ef416fc2 8 *
1a18c85c
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
1a18c85c 46 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAddCert: Adding certificate for PID %d", pid);
ef416fc2 47
48 /*
49 * Allocate memory for the certificate...
50 */
51
52 if ((cert = calloc(sizeof(cupsd_cert_t), 1)) == NULL)
53 return;
54
55 /*
56 * Fill in the certificate information...
57 */
58
0fa6c7fa
MS
59 cert->pid = pid;
60 cert->type = type;
ef416fc2 61 strlcpy(cert->username, username, sizeof(cert->username));
62
63 for (i = 0; i < 32; i ++)
41681883 64 cert->certificate[i] = hex[CUPS_RAND() & 15];
ef416fc2 65
66 /*
67 * Save the certificate to a file readable only by the User and Group
68 * (or root and SystemGroup for PID == 0)...
69 */
70
71 snprintf(filename, sizeof(filename), "%s/certs/%d", StateDir, pid);
72 unlink(filename);
73
74 if ((fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0400)) < 0)
75 {
76 cupsdLogMessage(CUPSD_LOG_ERROR,
b9faaae1 77 "Unable to create certificate file %s - %s",
ef416fc2 78 filename, strerror(errno));
79 free(cert);
80 return;
81 }
82
83 if (pid == 0)
84 {
fa73b229 85#ifdef HAVE_ACL_INIT
86 acl_t acl; /* ACL information */
87 acl_entry_t entry; /* ACL entry */
88 acl_permset_t permset; /* Permissions */
bd7854cb 89# ifdef HAVE_MBR_UID_TO_UUID
fa73b229 90 uuid_t group; /* Group ID */
bd7854cb 91# endif /* HAVE_MBR_UID_TO_UUID */
e53920b9 92 static int acls_not_supported = 0;
93 /* Only warn once */
fa73b229 94#endif /* HAVE_ACL_INIT */
95
96
ef416fc2 97 /*
98 * Root certificate...
99 */
100
101 fchmod(fd, 0440);
102 fchown(fd, RunUser, SystemGroupIDs[0]);
103
bd7854cb 104 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddCert: NumSystemGroups=%d",
105 NumSystemGroups);
106
fa73b229 107#ifdef HAVE_ACL_INIT
108 if (NumSystemGroups > 1)
109 {
110 /*
111 * Set POSIX ACLs for the root certificate so that all system
112 * groups can access it...
113 */
114
12f89d24
MS
115 int j; /* Looping var */
116
bd7854cb 117# ifdef HAVE_MBR_UID_TO_UUID
118 /*
119 * On MacOS X, ACLs use UUIDs instead of GIDs...
120 */
121
fa73b229 122 acl = acl_init(NumSystemGroups - 1);
123
124 for (i = 1; i < NumSystemGroups; i ++)
125 {
126 /*
127 * Add each group ID to the ACL...
128 */
129
12f89d24
MS
130 for (j = 0; j < i; j ++)
131 if (SystemGroupIDs[j] == SystemGroupIDs[i])
132 break;
133
134 if (j < i)
135 continue; /* Skip duplicate groups */
136
fa73b229 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 }
12f89d24 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
12f89d24
MS
188 for (j = 0; j < i; j ++)
189 if (SystemGroupIDs[j] == SystemGroupIDs[i])
190 break;
191
192 if (j < i)
193 continue; /* Skip duplicate groups */
194
bd7854cb 195 acl_create_entry(&acl, &entry);
196 acl_get_permset(entry, &permset);
197 acl_add_perm(permset, ACL_READ);
198 acl_set_tag_type(entry, ACL_GROUP);
199 acl_set_qualifier(entry, SystemGroupIDs + i);
200 acl_set_permset(entry, permset);
201 }
202
203 if (acl_valid(acl))
204 {
e53920b9 205 char *text, *textptr; /* Temporary string */
206
bd7854cb 207 cupsdLogMessage(CUPSD_LOG_ERROR, "ACL did not validate: %s",
208 strerror(errno));
209 text = acl_to_text(acl, NULL);
210 for (textptr = strchr(text, '\n');
211 textptr;
212 textptr = strchr(textptr + 1, '\n'))
213 *textptr = ',';
214
215 cupsdLogMessage(CUPSD_LOG_ERROR, "ACL: %s", text);
a2326b5b 216 acl_free(text);
bd7854cb 217 }
218# endif /* HAVE_MBR_UID_TO_UUID */
fa73b229 219
220 if (acl_set_fd(fd, acl))
e53920b9 221 {
222 if (errno != EOPNOTSUPP || !acls_not_supported)
223 cupsdLogMessage(CUPSD_LOG_ERROR,
224 "Unable to set ACLs on root certificate \"%s\" - %s",
225 filename, strerror(errno));
226
227 if (errno == EOPNOTSUPP)
228 acls_not_supported = 1;
229 }
230
fa73b229 231 acl_free(acl);
232 }
233#endif /* HAVE_ACL_INIT */
234
ef416fc2 235 RootCertTime = time(NULL);
236 }
237 else
238 {
239 /*
240 * CGI certificate...
241 */
242
243 fchmod(fd, 0400);
244 fchown(fd, User, Group);
245 }
246
247 DEBUG_printf(("ADD pid=%d, username=%s, cert=%s\n", pid, username,
248 cert->certificate));
249
250 write(fd, cert->certificate, strlen(cert->certificate));
251 close(fd);
252
253 /*
254 * Insert the certificate at the front of the list...
255 */
256
257 cert->next = Certs;
258 Certs = cert;
259}
260
261
262/*
263 * 'cupsdDeleteCert()' - Delete a single certificate.
264 */
265
266void
267cupsdDeleteCert(int pid) /* I - Process ID */
268{
269 cupsd_cert_t *cert, /* Current certificate */
270 *prev; /* Previous certificate */
271 char filename[1024]; /* Certificate file */
272
273
274 for (prev = NULL, cert = Certs; cert != NULL; prev = cert, cert = cert->next)
275 if (cert->pid == pid)
276 {
277 /*
278 * Remove this certificate from the list...
279 */
280
281 cupsdLogMessage(CUPSD_LOG_DEBUG2,
b9faaae1 282 "cupsdDeleteCert: Removing certificate for PID %d", pid);
ef416fc2 283
284 DEBUG_printf(("DELETE pid=%d, username=%s, cert=%s\n", cert->pid,
285 cert->username, cert->certificate));
286
287 if (prev == NULL)
288 Certs = cert->next;
289 else
290 prev->next = cert->next;
291
292 free(cert);
293
294 /*
295 * Delete the file and return...
296 */
297
298 snprintf(filename, sizeof(filename), "%s/certs/%d", StateDir, pid);
299 if (unlink(filename))
b9faaae1 300 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to remove %s!", filename);
ef416fc2 301
302 return;
303 }
304}
305
306
307/*
308 * 'cupsdDeleteAllCerts()' - Delete all certificates...
309 */
310
311void
312cupsdDeleteAllCerts(void)
313{
314 cupsd_cert_t *cert, /* Current certificate */
315 *next; /* Next certificate */
316 char filename[1024]; /* Certificate file */
317
318
319 /*
320 * Loop through each certificate, deleting them...
321 */
322
323 for (cert = Certs; cert != NULL; cert = next)
324 {
325 /*
326 * Delete the file...
327 */
328
329 snprintf(filename, sizeof(filename), "%s/certs/%d", StateDir, cert->pid);
330 if (unlink(filename))
b9faaae1 331 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to remove %s!", filename);
ef416fc2 332
333 /*
334 * Free memory...
335 */
336
337 next = cert->next;
338 free(cert);
339 }
340
e1d6a774 341 Certs = NULL;
342 RootCertTime = 0;
ef416fc2 343}
344
345
346/*
347 * 'cupsdFindCert()' - Find a certificate.
348 */
349
db0bd74a 350cupsd_cert_t * /* O - Matching certificate or NULL */
ef416fc2 351cupsdFindCert(const char *certificate) /* I - Certificate */
352{
353 cupsd_cert_t *cert; /* Current certificate */
354
355
b9faaae1
MS
356 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindCert(certificate=%s)",
357 certificate);
ef416fc2 358 for (cert = Certs; cert != NULL; cert = cert->next)
88f9aafc 359 if (!_cups_strcasecmp(certificate, cert->certificate))
ef416fc2 360 {
b9faaae1
MS
361 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindCert: Returning %s...",
362 cert->username);
db0bd74a 363 return (cert);
ef416fc2 364 }
365
b9faaae1 366 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindCert: Certificate not found!");
ef416fc2 367
368 return (NULL);
369}
370
371
372/*
373 * 'cupsdInitCerts()' - Initialize the certificate "system" and root
374 * certificate.
375 */
376
377void
378cupsdInitCerts(void)
379{
f8b3a85b 380#ifndef HAVE_ARC4RANDOM
ef416fc2 381 cups_file_t *fp; /* /dev/random file */
ef416fc2 382
383
384 /*
385 * Initialize the random number generator using the random device or
386 * the current time, as available...
387 */
388
389 if ((fp = cupsFileOpen("/dev/urandom", "rb")) == NULL)
390 {
f8b3a85b
MS
391 struct timeval tod; /* Time of day */
392
ef416fc2 393 /*
394 * Get the time in usecs and use it as the initial seed...
395 */
396
397 gettimeofday(&tod, NULL);
398
f8b3a85b 399 CUPS_SRAND((unsigned)(tod.tv_sec + tod.tv_usec));
ef416fc2 400 }
401 else
402 {
f8b3a85b
MS
403 unsigned seed; /* Seed for random number generator */
404
ef416fc2 405 /*
406 * Read 4 random characters from the random device and use
407 * them as the seed...
408 */
409
1a18c85c
MS
410 seed = (unsigned)cupsFileGetChar(fp);
411 seed = (seed << 8) | (unsigned)cupsFileGetChar(fp);
412 seed = (seed << 8) | (unsigned)cupsFileGetChar(fp);
413 CUPS_SRAND((seed << 8) | (unsigned)cupsFileGetChar(fp));
ef416fc2 414
415 cupsFileClose(fp);
416 }
f8b3a85b 417#endif /* !HAVE_ARC4RANDOM */
ef416fc2 418
419 /*
420 * Create a root certificate and return...
421 */
422
423 if (!RunUser)
0fa6c7fa 424 cupsdAddCert(0, "root", cupsdDefaultAuthType());
ef416fc2 425}
426
427
428/*
1a18c85c 429 * End of "$Id: cert.c 12034 2014-07-16 19:37:34Z msweet $".
ef416fc2 430 */