Dump PE32 module MD5 sums in lowercase for compaibility with md5sum(1).
[captive.git] / src / libcaptive / client / options-module.c
1 /* $Id$
2  * User options handling code of libcaptive
3  * Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
4  * 
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; exactly version 2 of June 1991 is required
8  * 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * 
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19
20 #include "config.h"
21
22 #include "captive/options.h"    /* self */
23 #include <glib/gmessages.h>
24 #include "captive/macros.h"
25 #include <glib/gstrfuncs.h>
26 #include <stdlib.h>
27 #include "captive/rtl-file.h"
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <sys/mman.h>
32 #include <openssl/md5.h>
33 #include <openssl/bn.h>
34 #include <openssl/crypto.h>
35
36
37 gboolean captive_options_module_load(struct captive_options_module *options_module,const gchar *pathname_utf8)
38 {
39         g_return_val_if_fail(options_module!=NULL,FALSE);
40         g_return_val_if_fail(pathname_utf8!=NULL,FALSE);
41
42         /* Open the Module */
43         options_module->type=CAPTIVE_OPTIONS_MODULE_TYPE_PE32;
44         options_module->pathname_utf8=g_strdup(pathname_utf8);
45         options_module->u.pe32.mapped=TRUE;
46         options_module->u.pe32.base=captive_rtl_file_mmap(
47                         &options_module->u.pe32.length, /* lenp */
48                         pathname_utf8,  /* path */
49                         O_RDONLY,       /* open_flags */
50                         PROT_READ,      /* mmap_prot */
51                         MAP_SHARED);    /* mmap_flags */
52         /* FIXME: convert errno instead of STATUS_INSUFFICIENT_RESOURCES */
53         g_return_val_if_fail(options_module->u.pe32.base!=NULL,FALSE);
54
55         if (options_module->u.pe32.length>=2
56                         && (('M'<<8U)|('Z'<<0U))==GUINT16_FROM_BE(*(const guint16 *)options_module->u.pe32.base)) {
57 unsigned char md5_bin[1+128/8]; /* 128 bits==16 bytes; '1+' for leading stub to prevent shorter output of BN_bn2hex() */
58 BIGNUM *bignum;
59 char *hex,*s;
60
61                 /* already done above */
62                 /* Calculate MD5 sum and convert it to hex string: */
63                 MD5(options_module->u.pe32.base,options_module->u.pe32.length,md5_bin+1);
64                 md5_bin[0]=0xFF;        /* stub to prevent shorter output of BN_bn2hex() */
65                 bignum=BN_bin2bn(md5_bin,1+128/8,NULL);
66                 hex=BN_bn2hex(bignum);
67                 g_assert(strlen(hex)==2*(1+128/8));
68                 options_module->u.pe32.md5=g_strdup(hex+2);
69                 OPENSSL_free(hex);
70                 BN_free(bignum);
71                 /* BN_bn2hex() returns uppercased string: */
72                 g_assert(strlen(options_module->u.pe32.md5)==32);
73                 for (s=options_module->u.pe32.md5;*s;s++) {
74                         g_assert(isxdigit(*s));
75                         *s=tolower(*s);
76                         g_assert(isxdigit(*s));
77                         }
78                 }
79         else {
80                 captive_rtl_file_munmap(options_module->u.pe32.base);
81                 options_module->type=CAPTIVE_OPTIONS_MODULE_TYPE_GMODULE;
82                 options_module->u.gmodule.pathname=g_strdup(pathname_utf8);
83                 }
84
85         return TRUE;
86 }
87
88
89 void captive_options_module_copy(struct captive_options_module *dest,const struct captive_options_module *src)
90 {
91         g_return_if_fail(dest!=NULL);
92         g_return_if_fail(src!=NULL);
93
94         dest->pathname_utf8=g_strdup(src->pathname_utf8);
95
96         dest->type=src->type;
97         switch (src->type) {
98                 case CAPTIVE_OPTIONS_MODULE_TYPE_EMPTY: g_assert_not_reached();
99
100                 case CAPTIVE_OPTIONS_MODULE_TYPE_PE32:
101                         dest->u.pe32.base=g_memdup(src->u.pe32.base,src->u.pe32.length);
102                         dest->u.pe32.length=src->u.pe32.length;
103                         dest->u.pe32.mapped=FALSE;
104                         dest->u.pe32.md5=g_strdup(src->u.pe32.md5);
105                         break;
106
107                 case CAPTIVE_OPTIONS_MODULE_TYPE_GMODULE:
108                         dest->u.gmodule.pathname=g_strdup(src->u.gmodule.pathname);
109                         break;
110
111                 default: g_assert_not_reached();
112                 }
113 }
114
115
116 void captive_options_module_free(struct captive_options_module *options_module)
117 {
118         g_return_if_fail(options_module!=NULL);
119
120         g_free(options_module->pathname_utf8);
121
122         switch (options_module->type) {
123                 case CAPTIVE_OPTIONS_MODULE_TYPE_EMPTY:
124                         break;
125
126                 case CAPTIVE_OPTIONS_MODULE_TYPE_PE32:
127                         if (options_module->u.pe32.mapped)
128                                 captive_rtl_file_munmap(options_module->u.pe32.base);
129                         else
130                                 g_free(options_module->u.pe32.base);
131                         g_free(options_module->u.pe32.md5);
132                         break;
133
134                 case CAPTIVE_OPTIONS_MODULE_TYPE_GMODULE:
135                         g_free(options_module->u.gmodule.pathname);
136                         break;
137
138                 default: g_assert_not_reached();
139                 }
140 }