Imported Upstream version 3.3.2
[debian/amanda] / device-src / s3-util.c
1 /*
2  * Copyright (c) 2008-2012 Zmanda, Inc.  All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License version 2 as published
6  * by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11  * for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16  *
17  * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
18  * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
19  */
20
21
22 #ifdef HAVE_CONFIG_H
23 /* use a relative path here to avoid conflicting with Perl's config.h. */
24 #include "../config/config.h"
25 #endif
26 #ifdef HAVE_REGEX_H
27 #include <sys/types.h>
28 #include <regex.h>
29 #endif
30 #ifdef HAVE_AMANDA_H
31 #include "amanda.h"
32 #endif
33
34 #include <glib.h>
35 #include <openssl/md5.h>
36 #include <openssl/bio.h>
37 #include <openssl/evp.h>
38 #include <openssl/bn.h>
39 #include "s3-util.h"
40
41 #ifdef HAVE_REGEX_H
42 int
43 s3_regexec_wrap(regex_t *regex,
44            const char *str,
45            size_t nmatch,
46            regmatch_t pmatch[],
47            int eflags)
48 {
49     char *message;
50     int size;
51     int reg_result;
52
53     reg_result = regexec(regex, str, nmatch, pmatch, eflags);
54     if (reg_result != 0 && reg_result != REG_NOMATCH) {
55         size = regerror(reg_result, regex, NULL, 0);
56         message = g_malloc(size);
57         regerror(reg_result, regex, message, size);
58
59         /* this is programmer error (bad regexp), so just log
60          * and abort().  There's no good way to signal a
61          * permanaent error from interpret_response. */
62         g_critical(_("Regex error: %s"), message);
63     }
64
65     return reg_result;
66 }
67 #else
68
69 int
70 s3_regexec_wrap(regex_t *regex,
71            const char *str,
72            size_t nmatch,
73            regmatch_t pmatch[],
74            int eflags)
75 {
76     GMatchInfo *match_info;
77     int ret = REG_NOERROR;
78     guint i;
79
80     g_assert(regex && *regex);
81     g_regex_match(*regex, str, eflags, &match_info);
82     if (g_match_info_matches(match_info)) {
83         g_assert(g_match_info_get_match_count(match_info) <= (glong) nmatch);
84         for (i = 0; i < nmatch; i++) {
85             pmatch[i].rm_eo = pmatch[i].rm_so = -1;
86             g_match_info_fetch_pos(match_info, i, &pmatch[i].rm_so, &pmatch[i].rm_eo);
87         }
88     } else {
89         ret = REG_NOMATCH;
90     }
91     g_match_info_free(match_info);
92     return ret;
93 }
94 #endif
95
96 #ifndef HAVE_AMANDA_H
97 char*
98 find_regex_substring(const char* base_string, const regmatch_t match)
99 {
100     g_assert(match.rm_eo >= match.rm_so);
101     return g_strndup(base_string+match.rm_so, match.rm_eo - match.rm_so);
102 }
103 #endif
104
105 gchar*
106 s3_base64_encode(const GByteArray *to_enc) {
107     BIO *bio_b64 = NULL, *bio_buff = NULL;
108     long bio_b64_len;
109     char *bio_b64_data = NULL, *ret = NULL;
110     if (!to_enc) return NULL;
111
112     /* Initialize base64 encoding filter */
113     bio_b64 = BIO_new(BIO_f_base64());
114     g_assert(bio_b64);
115     BIO_set_flags(bio_b64, BIO_FLAGS_BASE64_NO_NL);
116
117     /* Initialize memory buffer for the base64 encoding */
118     bio_buff = BIO_new(BIO_s_mem());
119     g_assert(bio_buff);
120     bio_buff = BIO_push(bio_b64, bio_buff);
121
122     /* Write the MD5 hash into the buffer to encode it in base64 */
123     BIO_write(bio_buff, to_enc->data, to_enc->len);
124     /* BIO_flush is a macro and GCC 4.1.2 complains without this cast*/
125     (void) BIO_flush(bio_buff);
126
127     /* Pull out the base64 encoding of the MD5 hash */
128     bio_b64_len = BIO_get_mem_data(bio_buff, &bio_b64_data);
129     g_assert(bio_b64_data);
130     ret = g_strndup(bio_b64_data, bio_b64_len);
131
132     /* If bio_b64 is freed separately, freeing bio_buff will
133      * invalidly free memory and potentially segfault.
134      */
135     BIO_free_all(bio_buff);
136     return ret;
137 }
138
139 gchar*
140 s3_hex_encode(const GByteArray *to_enc)  {
141     guint i;
142     gchar *ret = NULL, table[] = "0123456789abcdef";
143     if (!to_enc) return NULL;
144
145     ret = g_new(gchar, to_enc->len*2 + 1);
146     for (i = 0; i < to_enc->len; i++) {
147         /* most significant 4 bits */
148         ret[i*2] = table[to_enc->data[i] >> 4];
149         /* least significant 4 bits */
150         ret[i*2 + 1] = table[to_enc->data[i] & 0xf];
151     }
152     ret[to_enc->len*2] = '\0';
153
154     return ret;
155 }
156
157 GByteArray*
158 s3_compute_md5_hash(const GByteArray *to_hash) {
159     MD5_CTX md5_ctx;
160     GByteArray *ret;
161     if (!to_hash) return NULL;
162
163     ret = g_byte_array_sized_new(S3_MD5_HASH_BYTE_LEN);
164     g_byte_array_set_size(ret, S3_MD5_HASH_BYTE_LEN);
165
166     MD5_Init(&md5_ctx);
167     MD5_Update(&md5_ctx, to_hash->data, to_hash->len);
168     MD5_Final(ret->data, &md5_ctx);
169
170     return ret;
171 }