/*
- * "$Id: cert.c,v 1.7.2.5 2002/08/30 20:43:26 mike Exp $"
+ * "$Id$"
*
- * Authentication certificate routines for the Common UNIX
- * Printing System (CUPS).
+ * Authentication certificate routines for the CUPS scheduler.
*
- * Copyright 1997-2002 by Easy Software Products.
+ * Copyright 2007-2012 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
*
* These coded instructions, statements, and computer programs are the
- * property of Easy Software Products and are protected by Federal
- * copyright law. Distribution and use rights are outlined in the file
- * "LICENSE.txt" which should have been included with this file. If this
- * file is missing or damaged please contact Easy Software Products
- * at:
- *
- * Attn: CUPS Licensing Information
- * Easy Software Products
- * 44141 Airport View Drive, Suite 204
- * Hollywood, Maryland 20636-3111 USA
- *
- * Voice: (301) 373-9603
- * EMail: cups-info@cups.org
- * WWW: http://www.cups.org
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * which should have been included with this file. If this file is
+ * file is missing or damaged, see the license at "http://www.cups.org/".
*
* Contents:
*
- * AddCert() - Add a certificate.
- * DeleteCert() - Delete a single certificate.
- * DeleteAllCerts() - Delete all certificates...
- * FindCert() - Find a certificate.
- * InitCerts() - Initialize the certificate "system" and root
- * certificate.
+ * cupsdAddCert() - Add a certificate.
+ * cupsdDeleteCert() - Delete a single certificate.
+ * cupsdDeleteAllCerts() - Delete all certificates...
+ * cupsdFindCert() - Find a certificate.
+ * cupsdInitCerts() - Initialize the certificate "system" and root
+ * certificate.
*/
/*
*/
#include "cupsd.h"
-#include <grp.h>
+#ifdef HAVE_ACL_INIT
+# include <sys/acl.h>
+# ifdef HAVE_MEMBERSHIP_H
+# include <membership.h>
+# endif /* HAVE_MEMBERSHIP_H */
+#endif /* HAVE_ACL_INIT */
/*
- * 'AddCert()' - Add a certificate.
+ * 'cupsdAddCert()' - Add a certificate.
*/
void
-AddCert(int pid, /* I - Process ID */
- const char *username) /* I - Username */
+cupsdAddCert(int pid, /* I - Process ID */
+ const char *username, /* I - Username */
+ int type) /* I - AuthType for username */
{
int i; /* Looping var */
- cert_t *cert; /* Current certificate */
- FILE *fp; /* Certificate file */
+ cupsd_cert_t *cert; /* Current certificate */
+ int fd; /* Certificate file */
char filename[1024]; /* Certificate filename */
- struct group *grp; /* System group */
- static const char *hex = "0123456789ABCDEF";
+ static const char hex[] = "0123456789ABCDEF";
/* Hex constants... */
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdAddCert: Adding certificate for PID %d", pid);
+
/*
* Allocate memory for the certificate...
*/
- if ((cert = calloc(sizeof(cert_t), 1)) == NULL)
+ if ((cert = calloc(sizeof(cupsd_cert_t), 1)) == NULL)
return;
/*
* Fill in the certificate information...
*/
- cert->pid = pid;
+ cert->pid = pid;
+ cert->type = type;
strlcpy(cert->username, username, sizeof(cert->username));
for (i = 0; i < 32; i ++)
- cert->certificate[i] = hex[random() & 15];
+ cert->certificate[i] = hex[CUPS_RAND() & 15];
/*
* Save the certificate to a file readable only by the User and Group
* (or root and SystemGroup for PID == 0)...
*/
- snprintf(filename, sizeof(filename), "%s/certs/%d", ServerRoot, pid);
+ snprintf(filename, sizeof(filename), "%s/certs/%d", StateDir, pid);
+ unlink(filename);
- if ((fp = fopen(filename, "w")) == NULL)
+ if ((fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0400)) < 0)
{
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to create certificate file %s - %s",
+ filename, strerror(errno));
free(cert);
return;
}
if (pid == 0)
{
+#ifdef HAVE_ACL_INIT
+ acl_t acl; /* ACL information */
+ acl_entry_t entry; /* ACL entry */
+ acl_permset_t permset; /* Permissions */
+# ifdef HAVE_MBR_UID_TO_UUID
+ uuid_t group; /* Group ID */
+# endif /* HAVE_MBR_UID_TO_UUID */
+ static int acls_not_supported = 0;
+ /* Only warn once */
+#endif /* HAVE_ACL_INIT */
+
+
/*
* Root certificate...
*/
- fchmod(fileno(fp), 0440);
+ fchmod(fd, 0440);
+ fchown(fd, RunUser, SystemGroupIDs[0]);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddCert: NumSystemGroups=%d",
+ NumSystemGroups);
+
+#ifdef HAVE_ACL_INIT
+ if (NumSystemGroups > 1)
+ {
+ /*
+ * Set POSIX ACLs for the root certificate so that all system
+ * groups can access it...
+ */
+
+ int j; /* Looping var */
+
+# ifdef HAVE_MBR_UID_TO_UUID
+ /*
+ * On MacOS X, ACLs use UUIDs instead of GIDs...
+ */
+
+ acl = acl_init(NumSystemGroups - 1);
+
+ for (i = 1; i < NumSystemGroups; i ++)
+ {
+ /*
+ * Add each group ID to the ACL...
+ */
- if ((grp = getgrnam(SystemGroups[0])) == NULL)
- fchown(fileno(fp), getuid(), 0);
- else
- fchown(fileno(fp), getuid(), grp->gr_gid);
+ for (j = 0; j < i; j ++)
+ if (SystemGroupIDs[j] == SystemGroupIDs[i])
+ break;
- endgrent();
+ if (j < i)
+ continue; /* Skip duplicate groups */
+
+ acl_create_entry(&acl, &entry);
+ acl_get_permset(entry, &permset);
+ acl_add_perm(permset, ACL_READ_DATA);
+ acl_set_tag_type(entry, ACL_EXTENDED_ALLOW);
+ mbr_gid_to_uuid((gid_t)SystemGroupIDs[i], group);
+ acl_set_qualifier(entry, &group);
+ acl_set_permset(entry, permset);
+ }
+
+# else
+ /*
+ * POSIX ACLs need permissions for owner, group, other, and mask
+ * in addition to the rest of the system groups...
+ */
+
+ acl = acl_init(NumSystemGroups + 3);
+
+ /* Owner */
+ acl_create_entry(&acl, &entry);
+ acl_get_permset(entry, &permset);
+ acl_add_perm(permset, ACL_READ);
+ acl_set_tag_type(entry, ACL_USER_OBJ);
+ acl_set_permset(entry, permset);
+
+ /* Group */
+ acl_create_entry(&acl, &entry);
+ acl_get_permset(entry, &permset);
+ acl_add_perm(permset, ACL_READ);
+ acl_set_tag_type(entry, ACL_GROUP_OBJ);
+ acl_set_permset(entry, permset);
+
+ /* Others */
+ acl_create_entry(&acl, &entry);
+ acl_get_permset(entry, &permset);
+ acl_add_perm(permset, 0);
+ acl_set_tag_type(entry, ACL_OTHER);
+ acl_set_permset(entry, permset);
+
+ /* Mask */
+ acl_create_entry(&acl, &entry);
+ acl_get_permset(entry, &permset);
+ acl_add_perm(permset, ACL_READ);
+ acl_set_tag_type(entry, ACL_MASK);
+ acl_set_permset(entry, permset);
+
+ for (i = 1; i < NumSystemGroups; i ++)
+ {
+ /*
+ * Add each group ID to the ACL...
+ */
+
+ for (j = 0; j < i; j ++)
+ if (SystemGroupIDs[j] == SystemGroupIDs[i])
+ break;
+
+ if (j < i)
+ continue; /* Skip duplicate groups */
+
+ acl_create_entry(&acl, &entry);
+ acl_get_permset(entry, &permset);
+ acl_add_perm(permset, ACL_READ);
+ acl_set_tag_type(entry, ACL_GROUP);
+ acl_set_qualifier(entry, SystemGroupIDs + i);
+ acl_set_permset(entry, permset);
+ }
+
+ if (acl_valid(acl))
+ {
+ char *text, *textptr; /* Temporary string */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR, "ACL did not validate: %s",
+ strerror(errno));
+ text = acl_to_text(acl, NULL);
+ for (textptr = strchr(text, '\n');
+ textptr;
+ textptr = strchr(textptr + 1, '\n'))
+ *textptr = ',';
+
+ cupsdLogMessage(CUPSD_LOG_ERROR, "ACL: %s", text);
+ acl_free(text);
+ }
+# endif /* HAVE_MBR_UID_TO_UUID */
+
+ if (acl_set_fd(fd, acl))
+ {
+ if (errno != EOPNOTSUPP || !acls_not_supported)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to set ACLs on root certificate \"%s\" - %s",
+ filename, strerror(errno));
+
+ if (errno == EOPNOTSUPP)
+ acls_not_supported = 1;
+ }
+
+ acl_free(acl);
+ }
+#endif /* HAVE_ACL_INIT */
RootCertTime = time(NULL);
}
* CGI certificate...
*/
- fchmod(fileno(fp), 0400);
- fchown(fileno(fp), User, Group);
+ fchmod(fd, 0400);
+ fchown(fd, User, Group);
}
- fputs(cert->certificate, fp);
- fclose(fp);
+ DEBUG_printf(("ADD pid=%d, username=%s, cert=%s\n", pid, username,
+ cert->certificate));
+
+ write(fd, cert->certificate, strlen(cert->certificate));
+ close(fd);
/*
* Insert the certificate at the front of the list...
/*
- * 'DeleteCert()' - Delete a single certificate.
+ * 'cupsdDeleteCert()' - Delete a single certificate.
*/
void
-DeleteCert(int pid) /* I - Process ID */
+cupsdDeleteCert(int pid) /* I - Process ID */
{
- cert_t *cert, /* Current certificate */
+ cupsd_cert_t *cert, /* Current certificate */
*prev; /* Previous certificate */
char filename[1024]; /* Certificate file */
* Remove this certificate from the list...
*/
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdDeleteCert: Removing certificate for PID %d", pid);
+
+ DEBUG_printf(("DELETE pid=%d, username=%s, cert=%s\n", cert->pid,
+ cert->username, cert->certificate));
+
if (prev == NULL)
Certs = cert->next;
else
* Delete the file and return...
*/
- snprintf(filename, sizeof(filename), "%s/certs/%d", ServerRoot, pid);
- unlink(filename);
+ snprintf(filename, sizeof(filename), "%s/certs/%d", StateDir, pid);
+ if (unlink(filename))
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to remove %s!", filename);
return;
}
/*
- * 'DeleteAllCerts()' - Delete all certificates...
+ * 'cupsdDeleteAllCerts()' - Delete all certificates...
*/
void
-DeleteAllCerts(void)
+cupsdDeleteAllCerts(void)
{
- cert_t *cert, /* Current certificate */
+ cupsd_cert_t *cert, /* Current certificate */
*next; /* Next certificate */
char filename[1024]; /* Certificate file */
* Delete the file...
*/
- snprintf(filename, sizeof(filename), "%s/certs/%d", ServerRoot, cert->pid);
- unlink(filename);
+ snprintf(filename, sizeof(filename), "%s/certs/%d", StateDir, cert->pid);
+ if (unlink(filename))
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to remove %s!", filename);
/*
* Free memory...
free(cert);
}
- Certs = NULL;
+ Certs = NULL;
+ RootCertTime = 0;
}
/*
- * 'FindCert()' - Find a certificate.
+ * 'cupsdFindCert()' - Find a certificate.
*/
-const char * /* O - Matching username or NULL */
-FindCert(const char *certificate) /* I - Certificate */
+cupsd_cert_t * /* O - Matching certificate or NULL */
+cupsdFindCert(const char *certificate) /* I - Certificate */
{
- cert_t *cert; /* Current certificate */
+ cupsd_cert_t *cert; /* Current certificate */
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindCert(certificate=%s)",
+ certificate);
for (cert = Certs; cert != NULL; cert = cert->next)
- if (strcasecmp(certificate, cert->certificate) == 0)
- return (cert->username);
+ if (!_cups_strcasecmp(certificate, cert->certificate))
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindCert: Returning %s...",
+ cert->username);
+ return (cert);
+ }
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindCert: Certificate not found!");
return (NULL);
}
/*
- * 'InitCerts()' - Initialize the certificate "system" and root certificate.
+ * 'cupsdInitCerts()' - Initialize the certificate "system" and root
+ * certificate.
*/
void
-InitCerts(void)
+cupsdInitCerts(void)
{
- FILE *fp; /* /dev/random file */
- unsigned seed; /* Seed for random number generator */
- struct timeval tod; /* Time of day */
+#ifndef HAVE_ARC4RANDOM
+ cups_file_t *fp; /* /dev/random file */
/*
* the current time, as available...
*/
- if ((fp = fopen("/dev/urandom", "rb")) == NULL)
+ if ((fp = cupsFileOpen("/dev/urandom", "rb")) == NULL)
{
+ struct timeval tod; /* Time of day */
+
/*
* Get the time in usecs and use it as the initial seed...
*/
gettimeofday(&tod, NULL);
- seed = (unsigned)(tod.tv_sec + tod.tv_usec);
+ CUPS_SRAND((unsigned)(tod.tv_sec + tod.tv_usec));
}
else
{
+ unsigned seed; /* Seed for random number generator */
+
/*
* Read 4 random characters from the random device and use
* them as the seed...
*/
- seed = getc(fp);
- seed = (seed << 8) | getc(fp);
- seed = (seed << 8) | getc(fp);
- seed = (seed << 8) | getc(fp);
+ seed = cupsFileGetChar(fp);
+ seed = (seed << 8) | cupsFileGetChar(fp);
+ seed = (seed << 8) | cupsFileGetChar(fp);
+ CUPS_SRAND((seed << 8) | cupsFileGetChar(fp));
- fclose(fp);
+ cupsFileClose(fp);
}
-
- srandom(seed);
+#endif /* !HAVE_ARC4RANDOM */
/*
* Create a root certificate and return...
*/
- AddCert(0, "root");
+ if (!RunUser)
+ cupsdAddCert(0, "root", cupsdDefaultAuthType());
}
/*
- * End of "$Id: cert.c,v 1.7.2.5 2002/08/30 20:43:26 mike Exp $".
+ * End of "$Id$".
*/