Home | History | Annotate | Line # | Download | only in bsd-core
      1 /*-
      2  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
      3  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
      4  * All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice (including the next
     14  * paragraph) shall be included in all copies or substantial portions of the
     15  * Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     20  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     21  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     22  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     23  * OTHER DEALINGS IN THE SOFTWARE.
     24  *
     25  * Authors:
     26  *    Rickard E. (Rik) Faith <faith (at) valinux.com>
     27  *    Gareth Hughes <gareth (at) valinux.com>
     28  *
     29  */
     30 
     31 /** @file drm_auth.c
     32  * Implementation of the get/authmagic ioctls implementing the authentication
     33  * scheme between the master and clients.
     34  */
     35 
     36 #include "drmP.h"
     37 
     38 static int drm_hash_magic(drm_magic_t magic)
     39 {
     40 	return magic & (DRM_HASH_SIZE-1);
     41 }
     42 
     43 /**
     44  * Returns the file private associated with the given magic number.
     45  */
     46 static struct drm_file *drm_find_file(struct drm_device *dev, drm_magic_t magic)
     47 {
     48 	drm_magic_entry_t *pt;
     49 	int hash = drm_hash_magic(magic);
     50 
     51 	DRM_SPINLOCK_ASSERT(&dev->dev_lock);
     52 
     53 	for (pt = dev->magiclist[hash].head; pt; pt = pt->next) {
     54 		if (pt->magic == magic) {
     55 			return pt->priv;
     56 		}
     57 	}
     58 
     59 	return NULL;
     60 }
     61 
     62 /**
     63  * Inserts the given magic number into the hash table of used magic number
     64  * lists.
     65  */
     66 static int drm_add_magic(struct drm_device *dev, struct drm_file *priv,
     67 			 drm_magic_t magic)
     68 {
     69 	int		  hash;
     70 	drm_magic_entry_t *entry;
     71 
     72 	DRM_DEBUG("%d\n", magic);
     73 
     74 	DRM_SPINLOCK_ASSERT(&dev->dev_lock);
     75 
     76 	hash = drm_hash_magic(magic);
     77 	entry = malloc(sizeof(*entry), DRM_MEM_MAGIC, M_ZERO | M_NOWAIT);
     78 	if (!entry)
     79 		return ENOMEM;
     80 	entry->magic = magic;
     81 	entry->priv  = priv;
     82 	entry->next  = NULL;
     83 
     84 	if (dev->magiclist[hash].tail) {
     85 		dev->magiclist[hash].tail->next = entry;
     86 		dev->magiclist[hash].tail	= entry;
     87 	} else {
     88 		dev->magiclist[hash].head	= entry;
     89 		dev->magiclist[hash].tail	= entry;
     90 	}
     91 
     92 	return 0;
     93 }
     94 
     95 /**
     96  * Removes the given magic number from the hash table of used magic number
     97  * lists.
     98  */
     99 static int drm_remove_magic(struct drm_device *dev, drm_magic_t magic)
    100 {
    101 	drm_magic_entry_t *prev = NULL;
    102 	drm_magic_entry_t *pt;
    103 	int		  hash;
    104 
    105 	DRM_SPINLOCK_ASSERT(&dev->dev_lock);
    106 
    107 	DRM_DEBUG("%d\n", magic);
    108 	hash = drm_hash_magic(magic);
    109 
    110 	for (pt = dev->magiclist[hash].head; pt; prev = pt, pt = pt->next) {
    111 		if (pt->magic == magic) {
    112 			if (dev->magiclist[hash].head == pt) {
    113 				dev->magiclist[hash].head = pt->next;
    114 			}
    115 			if (dev->magiclist[hash].tail == pt) {
    116 				dev->magiclist[hash].tail = prev;
    117 			}
    118 			if (prev) {
    119 				prev->next = pt->next;
    120 			}
    121 			free(pt, DRM_MEM_MAGIC);
    122 			return 0;
    123 		}
    124 	}
    125 
    126 	return EINVAL;
    127 }
    128 
    129 /**
    130  * Called by the client, this returns a unique magic number to be authorized
    131  * by the master.
    132  *
    133  * The master may use its own knowledge of the client (such as the X
    134  * connection that the magic is passed over) to determine if the magic number
    135  * should be authenticated.
    136  */
    137 int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv)
    138 {
    139 	static drm_magic_t sequence = 0;
    140 	struct drm_auth *auth = data;
    141 
    142 	/* Find unique magic */
    143 	if (file_priv->magic) {
    144 		auth->magic = file_priv->magic;
    145 	} else {
    146 		DRM_LOCK();
    147 		do {
    148 			int old = sequence;
    149 
    150 			auth->magic = old+1;
    151 
    152 			if (!atomic_cmpset_int(&sequence, old, auth->magic))
    153 				continue;
    154 		} while (drm_find_file(dev, auth->magic));
    155 		file_priv->magic = auth->magic;
    156 		drm_add_magic(dev, file_priv, auth->magic);
    157 		DRM_UNLOCK();
    158 	}
    159 
    160 	DRM_DEBUG("%u\n", auth->magic);
    161 
    162 	return 0;
    163 }
    164 
    165 /**
    166  * Marks the client associated with the given magic number as authenticated.
    167  */
    168 int drm_authmagic(struct drm_device *dev, void *data,
    169 		  struct drm_file *file_priv)
    170 {
    171 	struct drm_auth *auth = data;
    172 	struct drm_file *priv;
    173 
    174 	DRM_DEBUG("%u\n", auth->magic);
    175 
    176 	DRM_LOCK();
    177 	priv = drm_find_file(dev, auth->magic);
    178 	if (priv != NULL) {
    179 		priv->authenticated = 1;
    180 		drm_remove_magic(dev, auth->magic);
    181 		DRM_UNLOCK();
    182 		return 0;
    183 	} else {
    184 		DRM_UNLOCK();
    185 		return EINVAL;
    186 	}
    187 }
    188