]>
git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/cert.c
eb34f673891fd77859dc49e692ca73139e3244ce
2 * Authentication certificate routines for the CUPS scheduler.
4 * Copyright 2007-2016 by Apple Inc.
5 * Copyright 1997-2006 by Easy Software Products.
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/".
15 * Include necessary headers...
21 # ifdef HAVE_MEMBERSHIP_H
22 # include <membership.h>
23 # endif /* HAVE_MEMBERSHIP_H */
24 #endif /* HAVE_ACL_INIT */
31 static int ctcompare(const char *a
, const char *b
);
35 * 'cupsdAddCert()' - Add a certificate.
39 cupsdAddCert(int pid
, /* I - Process ID */
40 const char *username
, /* I - Username */
41 int type
) /* I - AuthType for username */
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... */
51 cupsdLogMessage(CUPSD_LOG_DEBUG
, "cupsdAddCert: Adding certificate for PID %d", pid
);
54 * Allocate memory for the certificate...
57 if ((cert
= calloc(sizeof(cupsd_cert_t
), 1)) == NULL
)
61 * Fill in the certificate information...
66 strlcpy(cert
->username
, username
, sizeof(cert
->username
));
68 for (i
= 0; i
< 32; i
++)
69 cert
->certificate
[i
] = hex
[CUPS_RAND() & 15];
72 * Save the certificate to a file readable only by the User and Group
73 * (or root and SystemGroup for PID == 0)...
76 snprintf(filename
, sizeof(filename
), "%s/certs/%d", StateDir
, pid
);
79 if ((fd
= open(filename
, O_WRONLY
| O_CREAT
| O_EXCL
, 0400)) < 0)
81 cupsdLogMessage(CUPSD_LOG_ERROR
,
82 "Unable to create certificate file %s - %s",
83 filename
, strerror(errno
));
91 acl_t acl
; /* ACL information */
92 acl_entry_t entry
; /* ACL entry */
93 acl_permset_t permset
; /* Permissions */
94 # ifdef HAVE_MBR_UID_TO_UUID
95 uuid_t group
; /* Group ID */
96 # endif /* HAVE_MBR_UID_TO_UUID */
97 static int acls_not_supported
= 0;
99 #endif /* HAVE_ACL_INIT */
103 * Root certificate...
107 fchown(fd
, RunUser
, SystemGroupIDs
[0]);
109 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdAddCert: NumSystemGroups=%d", NumSystemGroups
);
112 if (NumSystemGroups
> 1)
115 * Set POSIX ACLs for the root certificate so that all system
116 * groups can access it...
119 int j
; /* Looping var */
121 # ifdef HAVE_MBR_UID_TO_UUID
123 * On macOS, ACLs use UUIDs instead of GIDs...
126 acl
= acl_init(NumSystemGroups
- 1);
128 for (i
= 1; i
< NumSystemGroups
; i
++)
131 * Add each group ID to the ACL...
134 for (j
= 0; j
< i
; j
++)
135 if (SystemGroupIDs
[j
] == SystemGroupIDs
[i
])
139 continue; /* Skip duplicate groups */
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
);
152 * POSIX ACLs need permissions for owner, group, other, and mask
153 * in addition to the rest of the system groups...
156 acl
= acl_init(NumSystemGroups
+ 3);
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
);
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
);
173 acl_create_entry(&acl
, &entry
);
174 acl_get_permset(entry
, &permset
);
175 acl_add_perm(permset
, 0);
176 acl_set_tag_type(entry
, ACL_OTHER
);
177 acl_set_permset(entry
, permset
);
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
);
186 for (i
= 1; i
< NumSystemGroups
; i
++)
189 * Add each group ID to the ACL...
192 for (j
= 0; j
< i
; j
++)
193 if (SystemGroupIDs
[j
] == SystemGroupIDs
[i
])
197 continue; /* Skip duplicate groups */
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
);
209 char *text
, *textptr
; /* Temporary string */
211 cupsdLogMessage(CUPSD_LOG_ERROR
, "ACL did not validate: %s",
213 text
= acl_to_text(acl
, NULL
);
214 for (textptr
= strchr(text
, '\n');
216 textptr
= strchr(textptr
+ 1, '\n'))
219 cupsdLogMessage(CUPSD_LOG_ERROR
, "ACL: %s", text
);
222 # endif /* HAVE_MBR_UID_TO_UUID */
224 if (acl_set_fd(fd
, acl
))
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
));
231 if (errno
== EOPNOTSUPP
)
232 acls_not_supported
= 1;
237 #endif /* HAVE_ACL_INIT */
239 RootCertTime
= time(NULL
);
248 fchown(fd
, User
, Group
);
251 DEBUG_printf(("ADD pid=%d, username=%s, cert=%s\n", pid
, username
,
254 write(fd
, cert
->certificate
, strlen(cert
->certificate
));
258 * Insert the certificate at the front of the list...
267 * 'cupsdDeleteCert()' - Delete a single certificate.
271 cupsdDeleteCert(int pid
) /* I - Process ID */
273 cupsd_cert_t
*cert
, /* Current certificate */
274 *prev
; /* Previous certificate */
275 char filename
[1024]; /* Certificate file */
278 for (prev
= NULL
, cert
= Certs
; cert
!= NULL
; prev
= cert
, cert
= cert
->next
)
279 if (cert
->pid
== pid
)
282 * Remove this certificate from the list...
285 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDeleteCert: Removing certificate for PID %d.", pid
);
287 DEBUG_printf(("DELETE pid=%d, username=%s, cert=%s\n", cert
->pid
,
288 cert
->username
, cert
->certificate
));
293 prev
->next
= cert
->next
;
298 * Delete the file and return...
301 snprintf(filename
, sizeof(filename
), "%s/certs/%d", StateDir
, pid
);
302 if (unlink(filename
))
303 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to remove %s!", filename
);
311 * 'cupsdDeleteAllCerts()' - Delete all certificates...
315 cupsdDeleteAllCerts(void)
317 cupsd_cert_t
*cert
, /* Current certificate */
318 *next
; /* Next certificate */
319 char filename
[1024]; /* Certificate file */
323 * Loop through each certificate, deleting them...
326 for (cert
= Certs
; cert
!= NULL
; cert
= next
)
332 snprintf(filename
, sizeof(filename
), "%s/certs/%d", StateDir
, cert
->pid
);
333 if (unlink(filename
))
334 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to remove %s!", filename
);
350 * 'cupsdFindCert()' - Find a certificate.
353 cupsd_cert_t
* /* O - Matching certificate or NULL */
354 cupsdFindCert(const char *certificate
) /* I - Certificate */
356 cupsd_cert_t
*cert
; /* Current certificate */
359 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdFindCert(certificate=%s)", certificate
);
360 for (cert
= Certs
; cert
!= NULL
; cert
= cert
->next
)
361 if (!ctcompare(certificate
, cert
->certificate
))
363 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdFindCert: Returning \"%s\".", cert
->username
);
367 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdFindCert: Certificate not found.");
374 * 'cupsdInitCerts()' - Initialize the certificate "system" and root
381 #ifndef HAVE_ARC4RANDOM
382 cups_file_t
*fp
; /* /dev/random file */
386 * Initialize the random number generator using the random device or
387 * the current time, as available...
390 if ((fp
= cupsFileOpen("/dev/urandom", "rb")) == NULL
)
392 struct timeval tod
; /* Time of day */
395 * Get the time in usecs and use it as the initial seed...
398 gettimeofday(&tod
, NULL
);
400 CUPS_SRAND((unsigned)(tod
.tv_sec
+ tod
.tv_usec
));
404 unsigned seed
; /* Seed for random number generator */
407 * Read 4 random characters from the random device and use
408 * them as the seed...
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
));
418 #endif /* !HAVE_ARC4RANDOM */
421 * Create a root certificate and return...
425 cupsdAddCert(0, "root", cupsdDefaultAuthType());
430 * 'ctcompare()' - Compare two strings in constant time.
433 static int /* O - 0 on match, non-zero on non-match */
434 ctcompare(const char *a
, /* I - First string */
435 const char *b
) /* I - Second string */
437 int result
= 0; /* Result */