+
+
+/*
+ **********************************************************************
+ * The following routines will be moved to a policy_posix.c module at
+ * some future point.
+ **********************************************************************
+ */
+
+/*
+ * posix_cred_create
+ *
+ * Description: Helper function to create a kauth_cred_t credential that is
+ * initally labelled with a specific POSIX credential label
+ *
+ * Parameters: pcred The posix_cred_t to use as the initial
+ * label value
+ *
+ * Returns: (kauth_cred_t) The credential that was found in the
+ * hash or creates
+ * NULL kauth_cred_add() failed, or there was
+ * no egid specified, or we failed to
+ * attach a label to the new credential
+ *
+ * Notes: This function currently wraps kauth_cred_create(), and is the
+ * only consumer of that ill-fated function, apart from bsd_init().
+ * It exists solely to support the NFS server code creation of
+ * credentials based on the over-the-wire RPC calls containing
+ * traditional POSIX credential information being tunneled to
+ * the server host from the client machine.
+ *
+ * In the future, we hope this function goes away.
+ *
+ * In the short term, it creates a temporary credential, puts
+ * the POSIX information from NFS into it, and then calls
+ * kauth_cred_create(), as an internal implementation detail.
+ *
+ * If we have to keep it around in the medium term, it will
+ * create a new kauth_cred_t, then label it with a POSIX label
+ * corresponding to the contents of the kauth_cred_t. If the
+ * policy_posix MACF module is not loaded, it will instead
+ * substitute a posix_cred_t which GRANTS all access (effectively
+ * a "root" credential) in order to not prevent NFS from working
+ * in the case that we are not supporting POSIX credentials.
+ */
+kauth_cred_t
+posix_cred_create(posix_cred_t pcred)
+{
+ struct ucred temp_cred;
+
+ bzero(&temp_cred, sizeof(temp_cred));
+ temp_cred.cr_posix = *pcred;
+
+ return kauth_cred_create(&temp_cred);
+}
+
+
+/*
+ * posix_cred_get
+ *
+ * Description: Given a kauth_cred_t, return the POSIX credential label, if
+ * any, which is associated with it.
+ *
+ * Parameters: cred The credential to obtain the label from
+ *
+ * Returns: posix_cred_t The POSIX credential label
+ *
+ * Notes: In the event that the policy_posix MACF module IS NOT loaded,
+ * this function will return a pointer to a posix_cred_t which
+ * GRANTS all access (effectively, a "root" credential). This is
+ * necessary to support legacy code which insists on tightly
+ * integrating POSIX credentials into its APIs, including, but
+ * not limited to, System V IPC mechanisms, POSIX IPC mechanisms,
+ * NFSv3, signals, dtrace, and a large number of kauth routines
+ * used to implement POSIX permissions related system calls.
+ *
+ * In the event that the policy_posix MACF module IS loaded, and
+ * there is no POSIX label on the kauth_cred_t credential, this
+ * function will return a pointer to a posix_cred_t which DENIES
+ * all access (effectively, a "deny rights granted by POSIX"
+ * credential). This is necessary to support the concept of a
+ * transiently loaded POSIX policy, or kauth_cred_t credentials
+ * which can not be used in conjunctions with POSIX permissions
+ * checks.
+ *
+ * This function currently returns the address of the cr_posix
+ * field of the supplied kauth_cred_t credential, and as such
+ * currently can not fail. In the future, this will not be the
+ * case.
+ */
+posix_cred_t
+posix_cred_get(kauth_cred_t cred)
+{
+ return(&cred->cr_posix);
+}
+
+
+/*
+ * posix_cred_label
+ *
+ * Description: Label a kauth_cred_t with a POSIX credential label
+ *
+ * Parameters: cred The credential to label
+ * pcred The POSIX credential t label it with
+ *
+ * Returns: (void)
+ *
+ * Notes: This function is currently void in order to permit it to fit
+ * in with the current MACF framework label methods which allow
+ * labeling to fail silently. This is like acceptable for
+ * mandatory access controls, but not for POSIX, since those
+ * access controls are advisory. We will need to consider a
+ * return value in a future version of the MACF API.
+ *
+ * This operation currently cannot fail, as currently the POSIX
+ * credential is a subfield of the kauth_cred_t (ucred), which
+ * MUST be valid. In the future, this will not be the case.
+ */
+void
+posix_cred_label(kauth_cred_t cred, posix_cred_t pcred)
+{
+ cred->cr_posix = *pcred; /* structure assign for now */
+}
+
+
+/*
+ * posix_cred_access
+ *
+ * Description: Perform a POSIX access check for a protected object
+ *
+ * Parameters: cred The credential to check
+ * object_uid The POSIX UID of the protected object
+ * object_gid The POSIX GID of the protected object
+ * object_mode The POSIX mode of the protected object
+ * mode_req The requested POSIX access rights
+ *
+ * Returns 0 Access is granted
+ * EACCES Access is denied
+ *
+ * Notes: This code optimizes the case where the world and group rights
+ * would both grant the requested rights to avoid making a group
+ * membership query. This is a big performance win in the case
+ * where this is true.
+ */
+int
+posix_cred_access(kauth_cred_t cred, id_t object_uid, id_t object_gid, mode_t object_mode, mode_t mode_req)
+{
+ int is_member;
+ mode_t mode_owner = (object_mode & S_IRWXU);
+ mode_t mode_group = (object_mode & S_IRWXG) << 3;
+ mode_t mode_world = (object_mode & S_IRWXO) << 6;
+
+ /*
+ * Check first for owner rights
+ */
+ if (kauth_cred_getuid(cred) == object_uid && (mode_req & mode_owner) == mode_req)
+ return (0);
+
+ /*
+ * Combined group and world rights check, if we don't have owner rights
+ *
+ * OPTIMIZED: If group and world rights would grant the same bits, and
+ * they set of requested bits is in both, then we can simply check the
+ * world rights, avoiding a group membership check, which is expensive.
+ */
+ if ((mode_req & mode_group & mode_world) == mode_req) {
+ return (0);
+ } else {
+ /*
+ * NON-OPTIMIZED: requires group membership check.
+ */
+ if ((mode_req & mode_group) != mode_req) {
+ /*
+ * exclusion group : treat errors as "is a member"
+ *
+ * NON-OPTIMIZED: +group would deny; must check group
+ */
+ if (!kauth_cred_ismember_gid(cred, object_gid, &is_member) && is_member) {
+ /*
+ * DENY: +group denies
+ */
+ return (EACCES);
+ } else {
+ if ((mode_req & mode_world) != mode_req) {
+ /*
+ * DENY: both -group & world would deny
+ */
+ return (EACCES);
+ } else {
+ /*
+ * ALLOW: allowed by -group and +world
+ */
+ return (0);
+ }
+ }
+ } else {
+ /*
+ * inclusion group; treat errors as "not a member"
+ *
+ * NON-OPTIMIZED: +group allows, world denies; must
+ * check group
+ */
+ if (!kauth_cred_ismember_gid(cred, object_gid, &is_member) && is_member) {
+ /*
+ * ALLOW: allowed by +group
+ */
+ return (0);
+ } else {
+ if ((mode_req & mode_world) != mode_req) {
+ /*
+ * DENY: both -group & world would deny
+ */
+ return (EACCES);
+ } else {
+ /*
+ * ALLOW: allowed by -group and +world
+ */
+ return (0);
+ }
+ }
+ }
+ }
+}