1/* 2 * "$Id: cert.c 12035 2014-07-16 19:40:05Z msweet $" 3 * 4 * Authentication certificate routines for the CUPS scheduler. 5 * 6 * Copyright 2007-2014 by Apple Inc. 7 * Copyright 1997-2006 by Easy Software Products. 8 * 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/". 14 */ 15 16/* 17 * Include necessary headers... 18 */ 19 20#include "cupsd.h" 21#ifdef HAVE_ACL_INIT 22# include <sys/acl.h> 23# ifdef HAVE_MEMBERSHIP_H 24# include <membership.h> 25# endif /* HAVE_MEMBERSHIP_H */ 26#endif /* HAVE_ACL_INIT */ 27 28 29/* 30 * 'cupsdAddCert()' - Add a certificate. 31 */ 32 33void 34cupsdAddCert(int pid, /* I - Process ID */ 35 const char *username, /* I - Username */ 36 int type) /* I - AuthType for username */ 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 46 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAddCert: Adding certificate for PID %d", pid); 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 59 cert->pid = pid; 60 cert->type = type; 61 strlcpy(cert->username, username, sizeof(cert->username)); 62 63 for (i = 0; i < 32; i ++) 64 cert->certificate[i] = hex[CUPS_RAND() & 15]; 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, 77 "Unable to create certificate file %s - %s", 78 filename, strerror(errno)); 79 free(cert); 80 return; 81 } 82 83 if (pid == 0) 84 { 85#ifdef HAVE_ACL_INIT 86 acl_t acl; /* ACL information */ 87 acl_entry_t entry; /* ACL entry */ 88 acl_permset_t permset; /* Permissions */ 89# ifdef HAVE_MBR_UID_TO_UUID 90 uuid_t group; /* Group ID */ 91# endif /* HAVE_MBR_UID_TO_UUID */ 92 static int acls_not_supported = 0; 93 /* Only warn once */ 94#endif /* HAVE_ACL_INIT */ 95 96 97 /* 98 * Root certificate... 99 */ 100 101 fchmod(fd, 0440); 102 fchown(fd, RunUser, SystemGroupIDs[0]); 103 104 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddCert: NumSystemGroups=%d", 105 NumSystemGroups); 106 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 115 int j; /* Looping var */ 116 117# ifdef HAVE_MBR_UID_TO_UUID 118 /* 119 * On MacOS X, ACLs use UUIDs instead of GIDs... 120 */ 121 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 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 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 } 145 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); 171 acl_add_perm(permset, 0); 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 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 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 { 205 char *text, *textptr; /* Temporary string */ 206 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); 216 acl_free(text); 217 } 218# endif /* HAVE_MBR_UID_TO_UUID */ 219 220 if (acl_set_fd(fd, acl)) 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 231 acl_free(acl); 232 } 233#endif /* HAVE_ACL_INIT */ 234 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, 282 "cupsdDeleteCert: Removing certificate for PID %d", pid); 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)) 300 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to remove %s!", filename); 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)) 331 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to remove %s!", filename); 332 333 /* 334 * Free memory... 335 */ 336 337 next = cert->next; 338 free(cert); 339 } 340 341 Certs = NULL; 342 RootCertTime = 0; 343} 344 345 346/* 347 * 'cupsdFindCert()' - Find a certificate. 348 */ 349 350cupsd_cert_t * /* O - Matching certificate or NULL */ 351cupsdFindCert(const char *certificate) /* I - Certificate */ 352{ 353 cupsd_cert_t *cert; /* Current certificate */ 354 355 356 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindCert(certificate=%s)", 357 certificate); 358 for (cert = Certs; cert != NULL; cert = cert->next) 359 if (!_cups_strcasecmp(certificate, cert->certificate)) 360 { 361 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindCert: Returning %s...", 362 cert->username); 363 return (cert); 364 } 365 366 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindCert: Certificate not found!"); 367 368 return (NULL); 369} 370 371 372/* 373 * 'cupsdInitCerts()' - Initialize the certificate "system" and root 374 * certificate. 375 */ 376 377void 378cupsdInitCerts(void) 379{ 380#ifndef HAVE_ARC4RANDOM 381 cups_file_t *fp; /* /dev/random file */ 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 { 391 struct timeval tod; /* Time of day */ 392 393 /* 394 * Get the time in usecs and use it as the initial seed... 395 */ 396 397 gettimeofday(&tod, NULL); 398 399 CUPS_SRAND((unsigned)(tod.tv_sec + tod.tv_usec)); 400 } 401 else 402 { 403 unsigned seed; /* Seed for random number generator */ 404 405 /* 406 * Read 4 random characters from the random device and use 407 * them as the seed... 408 */ 409 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)); 414 415 cupsFileClose(fp); 416 } 417#endif /* !HAVE_ARC4RANDOM */ 418 419 /* 420 * Create a root certificate and return... 421 */ 422 423 if (!RunUser) 424 cupsdAddCert(0, "root", cupsdDefaultAuthType()); 425} 426 427 428/* 429 * End of "$Id: cert.c 12035 2014-07-16 19:40:05Z msweet $". 430 */ 431