1    	/*
2    	 * Copyright (C) 2006-2010 Red Hat, Inc.
3    	 *
4    	 * Author: Steven Dake <sdake@redhat.com>
5    	 *
6    	 * This file is part of libqb.
7    	 *
8    	 * libqb is free software: you can redistribute it and/or modify
9    	 * it under the terms of the GNU Lesser General Public License as published by
10   	 * the Free Software Foundation, either version 2.1 of the License, or
11   	 * (at your option) any later version.
12   	 *
13   	 * libqb is distributed in the hope that it will be useful,
14   	 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15   	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   	 * GNU Lesser General Public License for more details.
17   	 *
18   	 * You should have received a copy of the GNU Lesser General Public License
19   	 * along with libqb.  If not, see <http://www.gnu.org/licenses/>.
20   	 */
21   	#include "os_base.h"
22   	
23   	#include <qb/qbhdb.h>
24   	#include <qb/qbatomic.h>
25   	
26   	enum QB_HDB_HANDLE_STATE {
27   		QB_HDB_HANDLE_STATE_EMPTY,
28   		QB_HDB_HANDLE_STATE_PENDINGREMOVAL,
29   		QB_HDB_HANDLE_STATE_ACTIVE
30   	};
31   	
32   	static void
33   	qb_hdb_create_first_run(struct qb_hdb *hdb)
34   	{
35   		if (hdb->first_run == QB_TRUE) {
36   			hdb->first_run = QB_FALSE;
37   			qb_atomic_init();
38   			hdb->handles = qb_array_create(32, sizeof(struct qb_hdb_handle));
39   		}
40   	}
41   	
42   	void
43   	qb_hdb_create(struct qb_hdb *hdb)
44   	{
45   		memset(hdb, 0, sizeof(struct qb_hdb));
46   		hdb->first_run = QB_TRUE;
47   		qb_hdb_create_first_run(hdb);
48   	}
49   	
50   	void
51   	qb_hdb_destroy(struct qb_hdb *hdb)
52   	{
53   		qb_array_free(hdb->handles);
54   		memset(hdb, 0, sizeof(struct qb_hdb));
55   	}
56   	
57   	int32_t
58   	qb_hdb_handle_create(struct qb_hdb *hdb, int32_t instance_size,
59   			     qb_handle_t * handle_id_out)
60   	{
61   		int32_t handle;
62   		int32_t res = 0;
63   		int32_t check;
64   		int32_t found = QB_FALSE;
65   		void *instance;
66   		int32_t i;
67   		struct qb_hdb_handle *entry = NULL;
68   		int32_t handle_count;
69   	
70   		qb_hdb_create_first_run(hdb);
71   	
72   		handle_count = qb_atomic_int_get(&hdb->handle_count);
73   		for (handle = 0; handle < handle_count; handle++) {
74   			if (qb_array_index(hdb->handles, handle, (void**)&entry) == 0 &&
75   			    entry->state == QB_HDB_HANDLE_STATE_EMPTY) {
76   				found = QB_TRUE;
77   				qb_atomic_int_inc(&entry->ref_count);
78   				break;
79   			}
80   		}
81   	
82   		if (found == QB_FALSE) {
83   			res = qb_array_grow(hdb->handles, handle_count + 1U);
84   			if (res != 0) {
85   				return res;
86   			}
87   			res = qb_array_index(hdb->handles, handle_count,
88   					     (void **)&entry);
89   			if (res != 0) {
90   				return res;
91   			}
92   			/* NB: qb_array_grow above guarantees that handle_count
93   			       will not overflow INT32_MAX */
94   			qb_atomic_int_inc((int32_t *)&hdb->handle_count);
95   		}
96   	
97   		instance = malloc(instance_size);
98   		if (instance == 0) {
99   			return -ENOMEM;
100  		}
101  	
102  		/*
103  		 * Make sure just positive integers are used for the integrity(?)
104  		 * checks within 2^32 address space, if we miss 200 times in a row
105  		 * (just 0 is concerned per specification of random), the PRNG may be
106  		 * broken -> the value is unspecified, subject of stack allocation.
107  		 */
108  		for (i = 0; i < 200; i++) {
(1) Event dont_call: "random" should not be used for security-related applications, because linear congruential algorithms are too easy to break.
(2) Event remediation: Use a compliant random number generator, such as "/dev/random" or "/dev/urandom" on Unix-like systems, and CNG (Cryptography API: Next Generation) on Windows.
109  			check = random();
110  	
111  			if (check > 0) {
112  				break;  /* covers also check == UINT32_MAX */
113  			}
114  		}
115  	
116  		memset(instance, 0, instance_size);
117  	
118  		entry->state = QB_HDB_HANDLE_STATE_ACTIVE;
119  		entry->instance = instance;
120  		entry->ref_count = 1;
121  		entry->check = check;
122  	
123  		*handle_id_out = (((uint64_t) (check)) << 32) | handle;
124  	
125  		return res;
126  	}
127  	
128  	int32_t
129  	qb_hdb_handle_get(struct qb_hdb * hdb, qb_handle_t handle_in, void **instance)
130  	{
131  		int32_t check = handle_in >> 32;
132  		int32_t handle = handle_in & UINT32_MAX;
133  		struct qb_hdb_handle *entry;
134  		int32_t handle_count;
135  	
136  		qb_hdb_create_first_run(hdb);
137  	
138  		*instance = NULL;
139  		handle_count = qb_atomic_int_get(&hdb->handle_count);
140  		if (handle >= handle_count) {
141  			return (-EBADF);
142  		}
143  	
144  		if (qb_array_index(hdb->handles, handle, (void **)&entry) != 0 ||
145  		    entry->state != QB_HDB_HANDLE_STATE_ACTIVE) {
146  			return (-EBADF);
147  		}
148  	
149  		if (check != (int32_t) UINT32_MAX && check != entry->check) {
150  			return (-EBADF);
151  		}
152  		qb_atomic_int_inc(&entry->ref_count);
153  	
154  		*instance = entry->instance;
155  	
156  		return (0);
157  	}
158  	
159  	int32_t
160  	qb_hdb_handle_get_always(struct qb_hdb * hdb, qb_handle_t handle_in,
161  				 void **instance)
162  	{
163  		return qb_hdb_handle_get(hdb, handle_in, instance);
164  	}
165  	
166  	int32_t
167  	qb_hdb_handle_put(struct qb_hdb * hdb, qb_handle_t handle_in)
168  	{
169  		int32_t check = handle_in >> 32;
170  		int32_t handle = handle_in & UINT32_MAX;
171  		struct qb_hdb_handle *entry;
172  		int32_t handle_count;
173  	
174  		qb_hdb_create_first_run(hdb);
175  	
176  		handle_count = qb_atomic_int_get(&hdb->handle_count);
177  		if (handle >= handle_count) {
178  			return (-EBADF);
179  		}
180  	
181  		if (qb_array_index(hdb->handles, handle, (void **)&entry) != 0 ||
182  		    (check != (int32_t) UINT32_MAX && check != entry->check)) {
183  			return (-EBADF);
184  		}
185  	
186  		if (qb_atomic_int_dec_and_test(&entry->ref_count)) {
187  			if (hdb->destructor) {
188  				hdb->destructor(entry->instance);
189  			}
190  			free(entry->instance);
191  			memset(entry, 0, sizeof(struct qb_hdb_handle));
192  		}
193  		return (0);
194  	}
195  	
196  	int32_t
197  	qb_hdb_handle_destroy(struct qb_hdb * hdb, qb_handle_t handle_in)
198  	{
199  		int32_t check = handle_in >> 32;
200  		int32_t handle = handle_in & UINT32_MAX;
201  		int32_t res;
202  		struct qb_hdb_handle *entry;
203  		int32_t handle_count;
204  	
205  		qb_hdb_create_first_run(hdb);
206  	
207  		handle_count = qb_atomic_int_get(&hdb->handle_count);
208  		if (handle >= handle_count) {
209  			return (-EBADF);
210  		}
211  	
212  		if (qb_array_index(hdb->handles, handle, (void **)&entry) != 0 ||
213  		    (check != (int32_t) UINT32_MAX && check != entry->check)) {
214  			return (-EBADF);
215  		}
216  	
217  		entry->state = QB_HDB_HANDLE_STATE_PENDINGREMOVAL;
218  		res = qb_hdb_handle_put(hdb, handle_in);
219  		return (res);
220  	}
221  	
222  	int32_t
223  	qb_hdb_handle_refcount_get(struct qb_hdb * hdb, qb_handle_t handle_in)
224  	{
225  		int32_t check = handle_in >> 32;
226  		int32_t handle = handle_in & UINT32_MAX;
227  		struct qb_hdb_handle *entry;
228  		int32_t handle_count;
229  		int32_t refcount = 0;
230  	
231  		qb_hdb_create_first_run(hdb);
232  	
233  		handle_count = qb_atomic_int_get(&hdb->handle_count);
234  		if (handle >= handle_count) {
235  			return (-EBADF);
236  		}
237  	
238  		if (qb_array_index(hdb->handles, handle, (void **)&entry) != 0 ||
239  		    (check != (int32_t) UINT32_MAX && check != entry->check)) {
240  			return (-EBADF);
241  		}
242  	
243  		refcount = qb_atomic_int_get(&entry->ref_count);
244  	
245  		return (refcount);
246  	}
247  	
248  	void
249  	qb_hdb_iterator_reset(struct qb_hdb *hdb)
250  	{
251  		hdb->iterator = 0;
252  	}
253  	
254  	int32_t
255  	qb_hdb_iterator_next(struct qb_hdb *hdb, void **instance, qb_handle_t * handle)
256  	{
257  		int32_t res = -1;
258  		uint64_t checker;
259  		struct qb_hdb_handle *entry;
260  		uint32_t handle_count;
261  	
262  		handle_count = qb_atomic_int_get(&hdb->handle_count);
263  		while (hdb->iterator < handle_count) {
264  			res = qb_array_index(hdb->handles,
265  					     hdb->iterator,
266  					     (void **)&entry);
267  			if (res != 0) {
268  				break;
269  			}
270  			checker = (uint64_t) (entry->check);
271  			*handle = (checker << 32) | hdb->iterator;
272  			res = qb_hdb_handle_get(hdb, *handle, instance);
273  	
274  			hdb->iterator += 1;
275  			if (res == 0) {
276  				break;
277  			}
278  		}
279  		return (res);
280  	}
281  	
282  	uint32_t
283  	qb_hdb_base_convert(qb_handle_t handle)
284  	{
285  		return (handle & UINT32_MAX);
286  	}
287  	
288  	uint64_t
289  	qb_hdb_nocheck_convert(uint32_t handle)
290  	{
291  		uint64_t retvalue = ((uint64_t) UINT32_MAX) << 32 | handle;
292  	
293  		return (retvalue);
294  	}
295