]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/cert.c
Load cups into easysw/current.
[thirdparty/cups.git] / scheduler / cert.c
1 /*
2 * "$Id: cert.c 5213 2006-03-02 00:37:34Z mike $"
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 #endif /* HAVE_ACL_INIT */
111
112
113 /*
114 * Root certificate...
115 */
116
117 fchmod(fd, 0440);
118 fchown(fd, RunUser, SystemGroupIDs[0]);
119
120 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddCert: NumSystemGroups=%d",
121 NumSystemGroups);
122
123 #ifdef HAVE_ACL_INIT
124 if (NumSystemGroups > 1)
125 {
126 /*
127 * Set POSIX ACLs for the root certificate so that all system
128 * groups can access it...
129 */
130
131 # ifdef HAVE_MBR_UID_TO_UUID
132 /*
133 * On MacOS X, ACLs use UUIDs instead of GIDs...
134 */
135
136 acl = acl_init(NumSystemGroups - 1);
137
138 for (i = 1; i < NumSystemGroups; i ++)
139 {
140 /*
141 * Add each group ID to the ACL...
142 */
143
144 acl_create_entry(&acl, &entry);
145 acl_get_permset(entry, &permset);
146 acl_add_perm(permset, ACL_READ_DATA);
147 acl_set_tag_type(entry, ACL_EXTENDED_ALLOW);
148 mbr_gid_to_uuid((gid_t)SystemGroupIDs[i], group);
149 acl_set_qualifier(entry, &group);
150 acl_set_permset(entry, permset);
151 }
152 # else
153 /*
154 * POSIX ACLs need permissions for owner, group, other, and mask
155 * in addition to the rest of the system groups...
156 */
157
158 acl = acl_init(NumSystemGroups + 3);
159
160 /* Owner */
161 acl_create_entry(&acl, &entry);
162 acl_get_permset(entry, &permset);
163 acl_add_perm(permset, ACL_READ);
164 acl_set_tag_type(entry, ACL_USER_OBJ);
165 acl_set_permset(entry, permset);
166
167 /* Group */
168 acl_create_entry(&acl, &entry);
169 acl_get_permset(entry, &permset);
170 acl_add_perm(permset, ACL_READ);
171 acl_set_tag_type(entry, ACL_GROUP_OBJ);
172 acl_set_permset(entry, permset);
173
174 /* Others */
175 acl_create_entry(&acl, &entry);
176 acl_get_permset(entry, &permset);
177 acl_add_perm(permset, 0);
178 acl_set_tag_type(entry, ACL_OTHER);
179 acl_set_permset(entry, permset);
180
181 /* Mask */
182 acl_create_entry(&acl, &entry);
183 acl_get_permset(entry, &permset);
184 acl_add_perm(permset, ACL_READ);
185 acl_set_tag_type(entry, ACL_MASK);
186 acl_set_permset(entry, permset);
187
188 for (i = 1; i < NumSystemGroups; i ++)
189 {
190 /*
191 * Add each group ID to the ACL...
192 */
193
194 acl_create_entry(&acl, &entry);
195 acl_get_permset(entry, &permset);
196 acl_add_perm(permset, ACL_READ);
197 acl_set_tag_type(entry, ACL_GROUP);
198 acl_set_qualifier(entry, SystemGroupIDs + i);
199 acl_set_permset(entry, permset);
200 }
201
202 if (acl_valid(acl))
203 {
204 char *text, *textptr;
205
206 cupsdLogMessage(CUPSD_LOG_ERROR, "ACL did not validate: %s",
207 strerror(errno));
208 text = acl_to_text(acl, NULL);
209 for (textptr = strchr(text, '\n');
210 textptr;
211 textptr = strchr(textptr + 1, '\n'))
212 *textptr = ',';
213
214 cupsdLogMessage(CUPSD_LOG_ERROR, "ACL: %s", text);
215 free(text);
216 }
217 # endif /* HAVE_MBR_UID_TO_UUID */
218
219 if (acl_set_fd(fd, acl))
220 cupsdLogMessage(CUPSD_LOG_ERROR,
221 "Unable to set ACLs on root certificate \"%s\" - %s",
222 filename, strerror(errno));
223 acl_free(acl);
224 }
225 #endif /* HAVE_ACL_INIT */
226
227 RootCertTime = time(NULL);
228 }
229 else
230 {
231 /*
232 * CGI certificate...
233 */
234
235 fchmod(fd, 0400);
236 fchown(fd, User, Group);
237 }
238
239 DEBUG_printf(("ADD pid=%d, username=%s, cert=%s\n", pid, username,
240 cert->certificate));
241
242 write(fd, cert->certificate, strlen(cert->certificate));
243 close(fd);
244
245 /*
246 * Insert the certificate at the front of the list...
247 */
248
249 cert->next = Certs;
250 Certs = cert;
251 }
252
253
254 /*
255 * 'cupsdDeleteCert()' - Delete a single certificate.
256 */
257
258 void
259 cupsdDeleteCert(int pid) /* I - Process ID */
260 {
261 cupsd_cert_t *cert, /* Current certificate */
262 *prev; /* Previous certificate */
263 char filename[1024]; /* Certificate file */
264
265
266 for (prev = NULL, cert = Certs; cert != NULL; prev = cert, cert = cert->next)
267 if (cert->pid == pid)
268 {
269 /*
270 * Remove this certificate from the list...
271 */
272
273 cupsdLogMessage(CUPSD_LOG_DEBUG2,
274 "cupsdDeleteCert: removing certificate for pid %d", pid);
275
276 DEBUG_printf(("DELETE pid=%d, username=%s, cert=%s\n", cert->pid,
277 cert->username, cert->certificate));
278
279 if (prev == NULL)
280 Certs = cert->next;
281 else
282 prev->next = cert->next;
283
284 free(cert);
285
286 /*
287 * Delete the file and return...
288 */
289
290 snprintf(filename, sizeof(filename), "%s/certs/%d", StateDir, pid);
291 if (unlink(filename))
292 cupsdLogMessage(CUPSD_LOG_ERROR,
293 "cupsdDeleteCert: Unable to remove %s!\n", filename);
294
295 return;
296 }
297 }
298
299
300 /*
301 * 'cupsdDeleteAllCerts()' - Delete all certificates...
302 */
303
304 void
305 cupsdDeleteAllCerts(void)
306 {
307 cupsd_cert_t *cert, /* Current certificate */
308 *next; /* Next certificate */
309 char filename[1024]; /* Certificate file */
310
311
312 /*
313 * Loop through each certificate, deleting them...
314 */
315
316 for (cert = Certs; cert != NULL; cert = next)
317 {
318 /*
319 * Delete the file...
320 */
321
322 snprintf(filename, sizeof(filename), "%s/certs/%d", StateDir, cert->pid);
323 if (unlink(filename))
324 cupsdLogMessage(CUPSD_LOG_ERROR,
325 "cupsdDeleteAllCerts: Unable to remove %s!\n", filename);
326
327 /*
328 * Free memory...
329 */
330
331 next = cert->next;
332 free(cert);
333 }
334
335 Certs = NULL;
336 }
337
338
339 /*
340 * 'cupsdFindCert()' - Find a certificate.
341 */
342
343 const char * /* O - Matching username or NULL */
344 cupsdFindCert(const char *certificate) /* I - Certificate */
345 {
346 cupsd_cert_t *cert; /* Current certificate */
347
348
349 DEBUG_printf(("cupsdFindCert(certificate=%s)\n", certificate));
350 for (cert = Certs; cert != NULL; cert = cert->next)
351 if (!strcasecmp(certificate, cert->certificate))
352 {
353 DEBUG_printf((" returning %s...\n", cert->username));
354 return (cert->username);
355 }
356
357 DEBUG_puts(" certificate not found!");
358
359 return (NULL);
360 }
361
362
363 /*
364 * 'cupsdInitCerts()' - Initialize the certificate "system" and root
365 * certificate.
366 */
367
368 void
369 cupsdInitCerts(void)
370 {
371 cups_file_t *fp; /* /dev/random file */
372 unsigned seed; /* Seed for random number generator */
373 struct timeval tod; /* Time of day */
374
375
376 /*
377 * Initialize the random number generator using the random device or
378 * the current time, as available...
379 */
380
381 if ((fp = cupsFileOpen("/dev/urandom", "rb")) == NULL)
382 {
383 /*
384 * Get the time in usecs and use it as the initial seed...
385 */
386
387 gettimeofday(&tod, NULL);
388
389 seed = (unsigned)(tod.tv_sec + tod.tv_usec);
390 }
391 else
392 {
393 /*
394 * Read 4 random characters from the random device and use
395 * them as the seed...
396 */
397
398 seed = cupsFileGetChar(fp);
399 seed = (seed << 8) | cupsFileGetChar(fp);
400 seed = (seed << 8) | cupsFileGetChar(fp);
401 seed = (seed << 8) | cupsFileGetChar(fp);
402
403 cupsFileClose(fp);
404 }
405
406 srandom(seed);
407
408 /*
409 * Create a root certificate and return...
410 */
411
412 if (!RunUser)
413 cupsdAddCert(0, "root");
414 }
415
416
417 /*
418 * End of "$Id: cert.c 5213 2006-03-02 00:37:34Z mike $".
419 */