]>
git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/cert.c
2 * Authentication certificate routines for the CUPS scheduler.
4 * Copyright 2007-2016 by Apple Inc.
5 * Copyright 1997-2006 by Easy Software Products.
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
11 * Include necessary headers...
17 # ifdef HAVE_MEMBERSHIP_H
18 # include <membership.h>
19 # endif /* HAVE_MEMBERSHIP_H */
20 #endif /* HAVE_ACL_INIT */
27 static int ctcompare(const char *a
, const char *b
);
31 * 'cupsdAddCert()' - Add a certificate.
35 cupsdAddCert(int pid
, /* I - Process ID */
36 const char *username
, /* I - Username */
37 int type
) /* I - AuthType for username */
39 int i
; /* Looping var */
40 cupsd_cert_t
*cert
; /* Current certificate */
41 int fd
; /* Certificate file */
42 char filename
[1024]; /* Certificate filename */
43 static const char hex
[] = "0123456789ABCDEF";
44 /* Hex constants... */
47 cupsdLogMessage(CUPSD_LOG_DEBUG
, "cupsdAddCert: Adding certificate for PID %d", pid
);
50 * Allocate memory for the certificate...
53 if ((cert
= calloc(sizeof(cupsd_cert_t
), 1)) == NULL
)
57 * Fill in the certificate information...
62 strlcpy(cert
->username
, username
, sizeof(cert
->username
));
64 for (i
= 0; i
< 32; i
++)
65 cert
->certificate
[i
] = hex
[CUPS_RAND() & 15];
68 * Save the certificate to a file readable only by the User and Group
69 * (or root and SystemGroup for PID == 0)...
72 snprintf(filename
, sizeof(filename
), "%s/certs/%d", StateDir
, pid
);
75 if ((fd
= open(filename
, O_WRONLY
| O_CREAT
| O_EXCL
, 0400)) < 0)
77 cupsdLogMessage(CUPSD_LOG_ERROR
,
78 "Unable to create certificate file %s - %s",
79 filename
, strerror(errno
));
87 acl_t acl
; /* ACL information */
88 acl_entry_t entry
; /* ACL entry */
89 acl_permset_t permset
; /* Permissions */
90 # ifdef HAVE_MBR_UID_TO_UUID
91 uuid_t group
; /* Group ID */
92 # endif /* HAVE_MBR_UID_TO_UUID */
93 static int acls_not_supported
= 0;
95 #endif /* HAVE_ACL_INIT */
103 fchown(fd
, RunUser
, SystemGroupIDs
[0]);
105 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdAddCert: NumSystemGroups=%d", NumSystemGroups
);
108 if (NumSystemGroups
> 1)
111 * Set POSIX ACLs for the root certificate so that all system
112 * groups can access it...
115 int j
; /* Looping var */
117 # ifdef HAVE_MBR_UID_TO_UUID
119 * On macOS, ACLs use UUIDs instead of GIDs...
122 acl
= acl_init(NumSystemGroups
- 1);
124 for (i
= 1; i
< NumSystemGroups
; i
++)
127 * Add each group ID to the ACL...
130 for (j
= 0; j
< i
; j
++)
131 if (SystemGroupIDs
[j
] == SystemGroupIDs
[i
])
135 continue; /* Skip duplicate groups */
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
);
148 * POSIX ACLs need permissions for owner, group, other, and mask
149 * in addition to the rest of the system groups...
152 acl
= acl_init(NumSystemGroups
+ 3);
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
);
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
);
169 acl_create_entry(&acl
, &entry
);
170 acl_get_permset(entry
, &permset
);
171 acl_add_perm(permset
, 0);
172 acl_set_tag_type(entry
, ACL_OTHER
);
173 acl_set_permset(entry
, permset
);
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
);
182 for (i
= 1; i
< NumSystemGroups
; i
++)
185 * Add each group ID to the ACL...
188 for (j
= 0; j
< i
; j
++)
189 if (SystemGroupIDs
[j
] == SystemGroupIDs
[i
])
193 continue; /* Skip duplicate groups */
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
);
205 char *text
, *textptr
; /* Temporary string */
207 cupsdLogMessage(CUPSD_LOG_ERROR
, "ACL did not validate: %s",
209 text
= acl_to_text(acl
, NULL
);
210 for (textptr
= strchr(text
, '\n');
212 textptr
= strchr(textptr
+ 1, '\n'))
215 cupsdLogMessage(CUPSD_LOG_ERROR
, "ACL: %s", text
);
218 # endif /* HAVE_MBR_UID_TO_UUID */
220 if (acl_set_fd(fd
, acl
))
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
));
227 if (errno
== EOPNOTSUPP
)
228 acls_not_supported
= 1;
233 #endif /* HAVE_ACL_INIT */
235 RootCertTime
= time(NULL
);
244 fchown(fd
, User
, Group
);
247 write(fd
, cert
->certificate
, strlen(cert
->certificate
));
251 * Insert the certificate at the front of the list...
260 * 'cupsdDeleteCert()' - Delete a single certificate.
264 cupsdDeleteCert(int pid
) /* I - Process ID */
266 cupsd_cert_t
*cert
, /* Current certificate */
267 *prev
; /* Previous certificate */
268 char filename
[1024]; /* Certificate file */
271 for (prev
= NULL
, cert
= Certs
; cert
!= NULL
; prev
= cert
, cert
= cert
->next
)
272 if (cert
->pid
== pid
)
275 * Remove this certificate from the list...
278 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDeleteCert: Removing certificate for PID %d.", pid
);
283 prev
->next
= cert
->next
;
288 * Delete the file and return...
291 snprintf(filename
, sizeof(filename
), "%s/certs/%d", StateDir
, pid
);
292 if (unlink(filename
))
293 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to remove %s!", filename
);
301 * 'cupsdDeleteAllCerts()' - Delete all certificates...
305 cupsdDeleteAllCerts(void)
307 cupsd_cert_t
*cert
, /* Current certificate */
308 *next
; /* Next certificate */
309 char filename
[1024]; /* Certificate file */
313 * Loop through each certificate, deleting them...
316 for (cert
= Certs
; cert
!= NULL
; cert
= next
)
322 snprintf(filename
, sizeof(filename
), "%s/certs/%d", StateDir
, cert
->pid
);
323 if (unlink(filename
))
324 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to remove %s!", filename
);
340 * 'cupsdFindCert()' - Find a certificate.
343 cupsd_cert_t
* /* O - Matching certificate or NULL */
344 cupsdFindCert(const char *certificate
) /* I - Certificate */
346 cupsd_cert_t
*cert
; /* Current certificate */
349 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdFindCert(certificate=%s)", certificate
);
350 for (cert
= Certs
; cert
!= NULL
; cert
= cert
->next
)
351 if (!ctcompare(certificate
, cert
->certificate
))
353 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdFindCert: Returning \"%s\".", cert
->username
);
357 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdFindCert: Certificate not found.");
364 * 'cupsdInitCerts()' - Initialize the certificate "system" and root
371 #ifndef HAVE_ARC4RANDOM
372 cups_file_t
*fp
; /* /dev/random file */
376 * Initialize the random number generator using the random device or
377 * the current time, as available...
380 if ((fp
= cupsFileOpen("/dev/urandom", "rb")) == NULL
)
382 struct timeval tod
; /* Time of day */
385 * Get the time in usecs and use it as the initial seed...
388 gettimeofday(&tod
, NULL
);
390 CUPS_SRAND((unsigned)(tod
.tv_sec
+ tod
.tv_usec
));
394 unsigned seed
; /* Seed for random number generator */
397 * Read 4 random characters from the random device and use
398 * them as the seed...
401 seed
= (unsigned)cupsFileGetChar(fp
);
402 seed
= (seed
<< 8) | (unsigned)cupsFileGetChar(fp
);
403 seed
= (seed
<< 8) | (unsigned)cupsFileGetChar(fp
);
404 CUPS_SRAND((seed
<< 8) | (unsigned)cupsFileGetChar(fp
));
408 #endif /* !HAVE_ARC4RANDOM */
411 * Create a root certificate and return...
415 cupsdAddCert(0, "root", cupsdDefaultAuthType());
420 * 'ctcompare()' - Compare two strings in constant time.
423 static int /* O - 0 on match, non-zero on non-match */
424 ctcompare(const char *a
, /* I - First string */
425 const char *b
) /* I - Second string */
427 int result
= 0; /* Result */