]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - scheduler/cert.c
Changelog.
[thirdparty/cups.git] / scheduler / cert.c
index f087fb163afbca25344361502aa2bd302957fc89..a2f8ff4f9aa420140eec5ed2930e13172c1f1dc1 100644 (file)
@@ -1,35 +1,25 @@
 /*
- * "$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);
   }
@@ -110,12 +250,15 @@ AddCert(int        pid,                   /* I - Process ID */
     * 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...
@@ -127,13 +270,13 @@ AddCert(int        pid,                   /* I - Process ID */
 
 
 /*
- * '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 */
 
@@ -145,6 +288,12 @@ DeleteCert(int pid)                        /* I - Process ID */
       * 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
@@ -156,8 +305,9 @@ DeleteCert(int pid)                 /* I - Process ID */
       * 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;
     }
@@ -165,13 +315,13 @@ DeleteCert(int pid)                       /* I - Process ID */
 
 
 /*
- * '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 */
 
@@ -186,8 +336,9 @@ DeleteAllCerts(void)
     * 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...
@@ -197,38 +348,47 @@ DeleteAllCerts(void)
     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 */
 
 
  /*
@@ -236,41 +396,45 @@ InitCerts(void)
   * 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$".
  */