]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/cert.c
Remove svn:keywords since they cause svn_load_dirs.pl to complain about every file.
[thirdparty/cups.git] / scheduler / cert.c
1 /*
2 * "$Id: cert.c 177 2006-06-21 00:20:03Z jlovell $"
3 *
4 * Authentication certificate routines for the Common UNIX
5 * Printing System (CUPS).
6 *
7 * Copyright 1997-2006 by Easy Software Products.
8 *
9 * These coded instructions, statements, and computer programs are the
10 * property of Easy Software Products and are protected by Federal
11 * copyright law. Distribution and use rights are outlined in the file
12 * "LICENSE.txt" which should have been included with this file. If this
13 * file is missing or damaged please contact Easy Software Products
14 * at:
15 *
16 * Attn: CUPS Licensing Information
17 * Easy Software Products
18 * 44141 Airport View Drive, Suite 204
19 * Hollywood, Maryland 20636 USA
20 *
21 * Voice: (301) 373-9600
22 * EMail: cups-info@cups.org
23 * WWW: http://www.cups.org
24 *
25 * Contents:
26 *
27 * cupsdAddCert() - Add a certificate.
28 * cupsdDeleteCert() - Delete a single certificate.
29 * cupsdDeleteAllCerts() - Delete all certificates...
30 * cupsdFindCert() - Find a certificate.
31 * cupsdInitCerts() - Initialize the certificate "system" and root
32 * certificate.
33 */
34
35 /*
36 * Include necessary headers...
37 */
38
39 #include "cupsd.h"
40 #ifdef HAVE_ACL_INIT
41 # include <sys/acl.h>
42 # ifdef HAVE_MEMBERSHIP_H
43 # include <membership.h>
44 # endif /* HAVE_MEMBERSHIP_H */
45 #endif /* HAVE_ACL_INIT */
46
47
48 /*
49 * 'cupsdAddCert()' - Add a certificate.
50 */
51
52 void
53 cupsdAddCert(int pid, /* I - Process ID */
54 const char *username) /* I - Username */
55 {
56 int i; /* Looping var */
57 cupsd_cert_t *cert; /* Current certificate */
58 int fd; /* Certificate file */
59 char filename[1024]; /* Certificate filename */
60 static const char hex[] = "0123456789ABCDEF";
61 /* Hex constants... */
62
63
64 cupsdLogMessage(CUPSD_LOG_DEBUG2,
65 "cupsdAddCert: adding certificate for pid %d", pid);
66
67 /*
68 * Allocate memory for the certificate...
69 */
70
71 if ((cert = calloc(sizeof(cupsd_cert_t), 1)) == NULL)
72 return;
73
74 /*
75 * Fill in the certificate information...
76 */
77
78 cert->pid = pid;
79 strlcpy(cert->username, username, sizeof(cert->username));
80
81 for (i = 0; i < 32; i ++)
82 cert->certificate[i] = hex[random() & 15];
83
84 /*
85 * Save the certificate to a file readable only by the User and Group
86 * (or root and SystemGroup for PID == 0)...
87 */
88
89 snprintf(filename, sizeof(filename), "%s/certs/%d", StateDir, pid);
90 unlink(filename);
91
92 if ((fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0400)) < 0)
93 {
94 cupsdLogMessage(CUPSD_LOG_ERROR,
95 "cupsdAddCert: Unable to create certificate file %s - %s",
96 filename, strerror(errno));
97 free(cert);
98 return;
99 }
100
101 if (pid == 0)
102 {
103 #ifdef HAVE_ACL_INIT
104 acl_t acl; /* ACL information */
105 acl_entry_t entry; /* ACL entry */
106 acl_permset_t permset; /* Permissions */
107 # ifdef HAVE_MBR_UID_TO_UUID
108 uuid_t group; /* Group ID */
109 # endif /* HAVE_MBR_UID_TO_UUID */
110 static int acls_not_supported = 0;
111 /* Only warn once */
112 #endif /* HAVE_ACL_INIT */
113
114
115 /*
116 * Root certificate...
117 */
118
119 fchmod(fd, 0440);
120 fchown(fd, RunUser, SystemGroupIDs[0]);
121
122 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddCert: NumSystemGroups=%d",
123 NumSystemGroups);
124
125 #ifdef HAVE_ACL_INIT
126 if (NumSystemGroups > 1)
127 {
128 /*
129 * Set POSIX ACLs for the root certificate so that all system
130 * groups can access it...
131 */
132
133 # ifdef HAVE_MBR_UID_TO_UUID
134 /*
135 * On MacOS X, ACLs use UUIDs instead of GIDs...
136 */
137
138 acl = acl_init(NumSystemGroups - 1);
139
140 for (i = 1; i < NumSystemGroups; i ++)
141 {
142 /*
143 * Add each group ID to the ACL...
144 */
145
146 acl_create_entry(&acl, &entry);
147 acl_get_permset(entry, &permset);
148 acl_add_perm(permset, ACL_READ_DATA);
149 acl_set_tag_type(entry, ACL_EXTENDED_ALLOW);
150 mbr_gid_to_uuid((gid_t)SystemGroupIDs[i], group);
151 acl_set_qualifier(entry, &group);
152 acl_set_permset(entry, permset);
153 }
154 # else
155 /*
156 * POSIX ACLs need permissions for owner, group, other, and mask
157 * in addition to the rest of the system groups...
158 */
159
160 acl = acl_init(NumSystemGroups + 3);
161
162 /* Owner */
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_USER_OBJ);
167 acl_set_permset(entry, permset);
168
169 /* Group */
170 acl_create_entry(&acl, &entry);
171 acl_get_permset(entry, &permset);
172 acl_add_perm(permset, ACL_READ);
173 acl_set_tag_type(entry, ACL_GROUP_OBJ);
174 acl_set_permset(entry, permset);
175
176 /* Others */
177 acl_create_entry(&acl, &entry);
178 acl_get_permset(entry, &permset);
179 acl_add_perm(permset, 0);
180 acl_set_tag_type(entry, ACL_OTHER);
181 acl_set_permset(entry, permset);
182
183 /* Mask */
184 acl_create_entry(&acl, &entry);
185 acl_get_permset(entry, &permset);
186 acl_add_perm(permset, ACL_READ);
187 acl_set_tag_type(entry, ACL_MASK);
188 acl_set_permset(entry, permset);
189
190 for (i = 1; i < NumSystemGroups; i ++)
191 {
192 /*
193 * Add each group ID to the ACL...
194 */
195
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 {
206 char *text, *textptr; /* Temporary string */
207
208
209 cupsdLogMessage(CUPSD_LOG_ERROR, "ACL did not validate: %s",
210 strerror(errno));
211 text = acl_to_text(acl, NULL);
212 for (textptr = strchr(text, '\n');
213 textptr;
214 textptr = strchr(textptr + 1, '\n'))
215 *textptr = ',';
216
217 cupsdLogMessage(CUPSD_LOG_ERROR, "ACL: %s", text);
218 free(text);
219 }
220 # endif /* HAVE_MBR_UID_TO_UUID */
221
222 if (acl_set_fd(fd, acl))
223 {
224 if (errno != EOPNOTSUPP || !acls_not_supported)
225 cupsdLogMessage(CUPSD_LOG_ERROR,
226 "Unable to set ACLs on root certificate \"%s\" - %s",
227 filename, strerror(errno));
228
229 if (errno == EOPNOTSUPP)
230 acls_not_supported = 1;
231 }
232
233 acl_free(acl);
234 }
235 #endif /* HAVE_ACL_INIT */
236
237 RootCertTime = time(NULL);
238 }
239 else
240 {
241 /*
242 * CGI certificate...
243 */
244
245 fchmod(fd, 0400);
246 fchown(fd, User, Group);
247 }
248
249 DEBUG_printf(("ADD pid=%d, username=%s, cert=%s\n", pid, username,
250 cert->certificate));
251
252 write(fd, cert->certificate, strlen(cert->certificate));
253 close(fd);
254
255 /*
256 * Insert the certificate at the front of the list...
257 */
258
259 cert->next = Certs;
260 Certs = cert;
261 }
262
263
264 /*
265 * 'cupsdDeleteCert()' - Delete a single certificate.
266 */
267
268 void
269 cupsdDeleteCert(int pid) /* I - Process ID */
270 {
271 cupsd_cert_t *cert, /* Current certificate */
272 *prev; /* Previous certificate */
273 char filename[1024]; /* Certificate file */
274
275
276 for (prev = NULL, cert = Certs; cert != NULL; prev = cert, cert = cert->next)
277 if (cert->pid == pid)
278 {
279 /*
280 * Remove this certificate from the list...
281 */
282
283 cupsdLogMessage(CUPSD_LOG_DEBUG2,
284 "cupsdDeleteCert: removing certificate for pid %d", pid);
285
286 DEBUG_printf(("DELETE pid=%d, username=%s, cert=%s\n", cert->pid,
287 cert->username, cert->certificate));
288
289 if (prev == NULL)
290 Certs = cert->next;
291 else
292 prev->next = cert->next;
293
294 free(cert);
295
296 /*
297 * Delete the file and return...
298 */
299
300 snprintf(filename, sizeof(filename), "%s/certs/%d", StateDir, pid);
301 if (unlink(filename))
302 cupsdLogMessage(CUPSD_LOG_ERROR,
303 "cupsdDeleteCert: Unable to remove %s!\n", filename);
304
305 return;
306 }
307 }
308
309
310 /*
311 * 'cupsdDeleteAllCerts()' - Delete all certificates...
312 */
313
314 void
315 cupsdDeleteAllCerts(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))
334 cupsdLogMessage(CUPSD_LOG_ERROR,
335 "cupsdDeleteAllCerts: Unable to remove %s!\n", filename);
336
337 /*
338 * Free memory...
339 */
340
341 next = cert->next;
342 free(cert);
343 }
344
345 Certs = NULL;
346 RootCertTime = 0;
347 }
348
349
350 /*
351 * 'cupsdFindCert()' - Find a certificate.
352 */
353
354 const char * /* O - Matching username or NULL */
355 cupsdFindCert(const char *certificate) /* I - Certificate */
356 {
357 cupsd_cert_t *cert; /* Current certificate */
358
359
360 DEBUG_printf(("cupsdFindCert(certificate=%s)\n", certificate));
361 for (cert = Certs; cert != NULL; cert = cert->next)
362 if (!strcasecmp(certificate, cert->certificate))
363 {
364 DEBUG_printf((" returning %s...\n", cert->username));
365 return (cert->username);
366 }
367
368 DEBUG_puts(" certificate not found!");
369
370 return (NULL);
371 }
372
373
374 /*
375 * 'cupsdInitCerts()' - Initialize the certificate "system" and root
376 * certificate.
377 */
378
379 void
380 cupsdInitCerts(void)
381 {
382 cups_file_t *fp; /* /dev/random file */
383 unsigned seed; /* Seed for random number generator */
384 struct timeval tod; /* Time of day */
385
386
387 /*
388 * Initialize the random number generator using the random device or
389 * the current time, as available...
390 */
391
392 if ((fp = cupsFileOpen("/dev/urandom", "rb")) == NULL)
393 {
394 /*
395 * Get the time in usecs and use it as the initial seed...
396 */
397
398 gettimeofday(&tod, NULL);
399
400 seed = (unsigned)(tod.tv_sec + tod.tv_usec);
401 }
402 else
403 {
404 /*
405 * Read 4 random characters from the random device and use
406 * them as the seed...
407 */
408
409 seed = cupsFileGetChar(fp);
410 seed = (seed << 8) | cupsFileGetChar(fp);
411 seed = (seed << 8) | cupsFileGetChar(fp);
412 seed = (seed << 8) | cupsFileGetChar(fp);
413
414 cupsFileClose(fp);
415 }
416
417 srandom(seed);
418
419 /*
420 * Create a root certificate and return...
421 */
422
423 if (!RunUser)
424 cupsdAddCert(0, "root");
425 }
426
427
428 /*
429 * End of "$Id: cert.c 177 2006-06-21 00:20:03Z jlovell $".
430 */