1 /* vi: set et sw=4 ts=4 cino=t0,(0: */
2 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
4 * This file is part of gsignond
6 * Copyright (C) 2013 Intel Corporation.
8 * Contact: Jussi Laako <jussi.laako@linux.intel.com>
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
33 #include "gsignond/gsignond-utils.h"
34 #include "gsignond/gsignond-log.h"
37 * SECTION:gsignond-utils
38 * @title: Utility functions
39 * @short_description: miscellaneous utility functions
40 * @include: gsignond/gsignond-utils.h
42 * Miscellaneous utility functions are described below.
45 typedef struct __nonce_ctx_t
53 static size_t pagesize = 0;
54 static _nonce_ctx_t _nonce_ctx = { 0, };
55 G_LOCK_DEFINE_STATIC (_nonce_lock);
59 * @filename: filename to wipe
61 * This function securely wipes the contents of the file, by overwriting it with
62 * 0's, then 1's, then random data. The file is then removed.
64 * Returns: TRUE if wiping and removal was successful.
67 gsignond_wipe_file (const gchar *filename)
69 gboolean retval = FALSE;
79 long confval = sysconf (_SC_PAGE_SIZE);
82 pagesize = (size_t) confval;
85 rngfd = open ("/dev/urandom", O_RDONLY);
89 wipefd = open (filename, O_WRONLY | O_SYNC);
92 wipebuf = g_malloc (pagesize);
93 if (fstat (wipefd, &filestat))
97 sizeleft = filestat.st_size;
98 memset (wipebuf, 0xff, pagesize);
100 writesize = (sizeleft < pagesize) ? sizeleft : pagesize;
101 sizewritten = write (wipefd, wipebuf, writesize);
102 if (sizewritten != (ssize_t) writesize)
104 sizeleft -= sizewritten;
107 if (lseek (wipefd, 0, SEEK_SET) == (off_t) -1)
111 sizeleft = filestat.st_size;
112 memset (wipebuf, 0x00, pagesize);
114 writesize = (sizeleft < pagesize) ? sizeleft : pagesize;
115 sizewritten = write (wipefd, wipebuf, writesize);
116 if (sizewritten != (ssize_t) writesize)
118 sizeleft -= sizewritten;
121 if (lseek (wipefd, 0, SEEK_SET) == (off_t) -1)
125 sizeleft = filestat.st_size;
127 writesize = (sizeleft < pagesize) ? sizeleft : pagesize;
128 if (read (rngfd, wipebuf, writesize) != (ssize_t) writesize)
130 sizewritten = write (wipefd, wipebuf, writesize);
131 if (sizewritten != (ssize_t) writesize)
133 sizeleft -= sizewritten;
136 /* don't leave traces of last pattern to the memory */
137 memset (wipebuf, 0x00, pagesize);
139 /* remove the file and set return value on success */
140 if (unlink (filename) == 0) {
142 DBG ("successfully wiped file %s", filename);
154 * gsignond_wipe_directory:
155 * @dirname: directory to wipe
157 * This function securely wipes the contents of the directory by calling
158 * gsignond_wipe_file() on each file. It also removes links and empty directories but
159 * does not recursively wipe them.
161 * Returns: TRUE if wiping and removal was successful.
164 gsignond_wipe_directory (const gchar *dirname)
166 gboolean retval = FALSE;
168 const gchar *filename;
171 struct stat stat_entry;
173 DBG ("wipe directory %s", dirname);
174 dirctx = g_dir_open (dirname, 0, NULL);
177 while ((filename = g_dir_read_name (dirctx))) {
178 filepath = g_build_filename (dirname, filename, NULL);
179 if (lstat(filepath, &stat_entry))
181 if (S_ISDIR (stat_entry.st_mode) ||
182 S_ISLNK (stat_entry.st_mode)) {
183 DBG ("remove directory or link %s", filepath);
184 wiperes = (remove (filepath) == 0);
186 DBG ("wipe file %s", filepath);
187 wiperes = gsignond_wipe_file (filepath);
196 g_dir_close (dirctx);
203 if (G_LIKELY(_nonce_ctx.initialized))
208 fd = open ("/dev/urandom", O_RDONLY);
211 if (read (fd, _nonce_ctx.key, sizeof (_nonce_ctx.key)) !=
212 sizeof (_nonce_ctx.key))
214 if (read (fd, _nonce_ctx.entropy, sizeof(_nonce_ctx.entropy)) !=
215 sizeof (_nonce_ctx.entropy))
218 _nonce_ctx.serial = 0;
220 _nonce_ctx.initialized = TRUE;
226 return _nonce_ctx.initialized;
230 * gsignond_generate_nonce:
232 * This function generates a random secure nonce using SHA1 HMAC.
234 * Returns: (transfer full): the nonce in lowercase hexadecimal format, 40 bytes long.
237 gsignond_generate_nonce ()
243 G_LOCK (_nonce_lock);
245 if (G_UNLIKELY (!_init_nonce_gen()))
248 hmac = g_hmac_new (G_CHECKSUM_SHA1,
249 _nonce_ctx.key, sizeof (_nonce_ctx.key));
250 g_hmac_update (hmac, _nonce_ctx.entropy, sizeof (_nonce_ctx.entropy));
253 (const guchar *) &_nonce_ctx.serial,
254 sizeof (_nonce_ctx.serial));
255 if (clock_gettime (CLOCK_MONOTONIC, &ts) == 0)
256 g_hmac_update (hmac, (const guchar *) &ts, sizeof (ts));
257 memset (&ts, 0x00, sizeof(ts));
258 nonce = g_strdup (g_hmac_get_string (hmac));
262 G_UNLOCK (_nonce_lock);
274 return g_strcmp0 (a,b);
278 * gsignond_sequence_to_variant:
279 * @seq: Sequence of strings to convert
281 * Convert a string sequence to a variant.
283 * Returns: (transfer full): #GVariant of type "as".
286 gsignond_sequence_to_variant (GSequence *seq)
288 GSequenceIter * iter = NULL;
289 GVariant *var = NULL;
290 GVariantBuilder builder;
292 if (!seq) return NULL;
294 g_variant_builder_init (&builder, G_VARIANT_TYPE_STRING_ARRAY);
295 iter = g_sequence_get_begin_iter (seq);
296 while (!g_sequence_iter_is_end (iter)) {
297 const gchar * d = g_sequence_get (iter);
298 g_variant_builder_add (&builder, "s", d);
299 iter = g_sequence_iter_next (iter);
301 var = g_variant_builder_end (&builder);
306 * gsignond_variant_to_sequence:
307 * @var: Variant of "as" to convert
309 * Convert variant containing string array to sequence.
311 * Returns: (transfer full): #GSequence of strings
314 gsignond_variant_to_sequence (GVariant *var)
317 GSequence *seq = NULL;
320 if (!var) return NULL;
322 seq = g_sequence_new ((GDestroyNotify)g_free);
323 g_variant_iter_init (&iter, var);
324 while (g_variant_iter_next (&iter, "s", &item)) {
325 g_sequence_insert_sorted (seq,
327 (GCompareDataFunc) _compare_strings,
334 * gsignond_sequence_to_array:
335 * @seq: Sequence of strings to convert
337 * Convert sequence of strings to null-terminated string array.
339 * Returns: (transfer full): Null-terminated array of strings
342 gsignond_sequence_to_array (GSequence *seq)
344 gchar **items, **temp;
347 if (!seq) return NULL;
349 items = g_malloc0 ((g_sequence_get_length (seq) + 1) * sizeof (gchar *));
351 for (iter = g_sequence_get_begin_iter (seq);
352 iter != g_sequence_get_end_iter (seq);
353 iter = g_sequence_iter_next (iter)) {
354 *temp = g_sequence_get (iter);
361 * gsignond_array_to_sequence:
362 * @items: (transfer full): Null-terminated array of strings to convert
364 * Convert null-terminated array of strings to a sequence.
366 * Returns: (transfer full): #GSequence of strings
369 gsignond_array_to_sequence (gchar **items)
371 gchar **item_iter = items;
372 GSequence *seq = NULL;
374 if (!items) return NULL;
376 seq = g_sequence_new ((GDestroyNotify) g_free);
378 g_sequence_insert_sorted (seq,
380 (GCompareDataFunc) _compare_strings,
389 * gsignond_copy_array_to_sequence:
390 * @items: Null-terminated array of strings to copy
392 * Copy null-terminated array of strings to a sequence.
394 * Returns: (transfer full): #GSequence of strings
397 gsignond_copy_array_to_sequence (const gchar **items)
399 GSequence *seq = NULL;
401 if (!items) return NULL;
403 seq = g_sequence_new ((GDestroyNotify) g_free);
405 g_sequence_insert_sorted (seq,
407 (GCompareDataFunc) _compare_strings,
415 * gsignond_is_host_in_domain:
416 * @domain: a domain name
419 * Checks if @host belongs to @domain.
421 * Returns: the result
424 gsignond_is_host_in_domain(const gchar *host, const gchar *domain)
426 gchar** domain_parts = g_strsplit(domain, ".", 0);
427 gchar** host_parts = g_strsplit(host, ".", 0);
428 gchar** truncated_host_parts = host_parts;
430 guint domain_parts_n = g_strv_length(domain_parts);
431 guint host_parts_n = g_strv_length(host_parts);
433 gint extra_host_parts_n = host_parts_n - domain_parts_n;
435 while (extra_host_parts_n > 0) {
436 truncated_host_parts++;
437 extra_host_parts_n--;
439 gchar* truncated_host = g_strjoinv(".", truncated_host_parts);
440 gint result = g_strcmp0(domain, truncated_host);
442 g_free(truncated_host);
443 g_strfreev(host_parts);
444 g_strfreev(domain_parts);
446 return result == 0 ? TRUE : FALSE;