Provide statical linking of GnomeVFS "libntfs" method for: --enable-standalone
[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 #include <ctype.h>
36
37
38 static void module_check_captivemodid(struct captive_options_module *options_module,const gchar *pathname_utf8)
39 {
40 #ifdef HAVE_LIBXML_XMLREADER_H
41         if (!captive_options->captivemodid) {
42                 if (!captive_options->load_untested)
43                         g_error(_(
44                                         "You do not have loaded any .captivemodid.xml database using: --modid-path\n"
45                                         "Unable to check MS-Windows module file validity. You should load the database first.\n"
46                                         "You may also force loading of the module although it may not be tested: --load-untested"));
47                 g_message(_("Loading possibly INCOMPATIBLE module as no database is present. Forced by: --load-untested: %s"),
48                                 pathname_utf8);
49                 return;
50                 }
51         if (captive_captivemodid_module_md5_lookup(captive_options->captivemodid,options_module->u.pe32.md5))
52                 return;
53         if (!captive_options->load_untested)
54                 g_error(_(
55                                 "Attempted to load UNTESTED and possibly INCOMPATIBLE module: %s\n"
56                                 "You should get more recent identifications database: %s\n"
57                                 "Otherwise you may also force the loading by the option: --load-untested"),
58                                 pathname_utf8,captive_captivemodid_get_pathname_loaded(captive_options->captivemodid));
59         g_message(_(
60                         "Loading UNTESTED and possibly INCOMPATIBLE module: %s\n"
61                         "Although forced by --load-untested you really should get more recent modid database: %s\n"),
62                         pathname_utf8,captive_captivemodid_get_pathname_loaded(captive_options->captivemodid));
63 #endif /* HAVE_LIBXML_XMLREADER_H */
64 }
65
66 gboolean captive_options_module_load(struct captive_options_module *options_module,const gchar *pathname_utf8)
67 {
68 const guint8 magic_mscf[]={'M','S','C','F',0,0,0,0};
69
70         g_return_val_if_fail(options_module!=NULL,FALSE);
71         g_return_val_if_fail(pathname_utf8!=NULL,FALSE);
72
73         /* Open the Module */
74         options_module->type=CAPTIVE_OPTIONS_MODULE_TYPE_PE32;
75         options_module->pathname_utf8=g_strdup(pathname_utf8);
76         options_module->u.pe32.mapped=TRUE;
77         options_module->u.pe32.base=captive_rtl_file_mmap(
78                         &options_module->u.pe32.length, /* lenp */
79                         pathname_utf8,  /* path */
80                         O_RDONLY,       /* open_flags */
81                         PROT_READ,      /* mmap_prot */
82                         MAP_SHARED);    /* mmap_flags */
83         /* FIXME: convert errno instead of STATUS_INSUFFICIENT_RESOURCES */
84         g_return_val_if_fail(options_module->u.pe32.base!=NULL,FALSE);
85
86         if (options_module->u.pe32.length>=2
87                         && (('M'<<8U)|('Z'<<0U))==GUINT16_FROM_BE(*(const guint16 *)options_module->u.pe32.base)) {
88 unsigned char md5_bin[1+128/8]; /* 128 bits==16 bytes; '1+' for leading stub to prevent shorter output of BN_bn2hex() */
89 BIGNUM *bignum;
90 char *hex,*s;
91
92                 /* already done above */
93                 /* Calculate MD5 sum and convert it to hex string: */
94                 MD5(options_module->u.pe32.base,options_module->u.pe32.length,md5_bin+1);
95                 md5_bin[0]=0xFF;        /* stub to prevent shorter output of BN_bn2hex() */
96                 bignum=BN_bin2bn(md5_bin,1+128/8,NULL);
97                 hex=BN_bn2hex(bignum);
98                 g_assert(strlen(hex)==2*(1+128/8));
99                 options_module->u.pe32.md5=g_strdup(hex+2);
100                 OPENSSL_free(hex);
101                 BN_free(bignum);
102                 /* BN_bn2hex() returns uppercased string: */
103                 g_assert(strlen(options_module->u.pe32.md5)==32);
104                 for (s=options_module->u.pe32.md5;*s;s++) {
105                         g_assert(isxdigit(*s));
106                         *s=tolower(*s);
107                         g_assert(isxdigit(*s));
108                         }
109                 module_check_captivemodid(options_module,pathname_utf8);
110                 }
111         else if (options_module->u.pe32.length>=sizeof(magic_mscf)
112                         && !memcmp(options_module->u.pe32.base,magic_mscf,sizeof(magic_mscf))) {
113                 g_error(_("Compressed cabinet file (\"*.??_\") not loadable - you must use cabextract(1) or EXPAND.EXE first: %s"),
114                                 pathname_utf8);
115                 }
116         else {
117                 captive_rtl_file_munmap(options_module->u.pe32.base);
118                 options_module->type=CAPTIVE_OPTIONS_MODULE_TYPE_GMODULE;
119                 options_module->u.gmodule.pathname=g_strdup(pathname_utf8);
120                 }
121
122         return TRUE;
123 }
124
125
126 void captive_options_module_copy(struct captive_options_module *dest,const struct captive_options_module *src)
127 {
128         g_return_if_fail(dest!=NULL);
129         g_return_if_fail(src!=NULL);
130
131         dest->pathname_utf8=g_strdup(src->pathname_utf8);
132
133         dest->type=src->type;
134         switch (src->type) {
135                 case CAPTIVE_OPTIONS_MODULE_TYPE_EMPTY: g_assert_not_reached();
136
137                 case CAPTIVE_OPTIONS_MODULE_TYPE_PE32:
138                         dest->u.pe32.base=g_memdup(src->u.pe32.base,src->u.pe32.length);
139                         dest->u.pe32.length=src->u.pe32.length;
140                         dest->u.pe32.mapped=FALSE;
141                         dest->u.pe32.md5=g_strdup(src->u.pe32.md5);
142                         break;
143
144                 case CAPTIVE_OPTIONS_MODULE_TYPE_GMODULE:
145                         dest->u.gmodule.pathname=g_strdup(src->u.gmodule.pathname);
146                         break;
147
148                 default: g_assert_not_reached();
149                 }
150 }
151
152
153 void captive_options_module_free(struct captive_options_module *options_module)
154 {
155         g_return_if_fail(options_module!=NULL);
156
157         g_free(options_module->pathname_utf8);
158
159         switch (options_module->type) {
160                 case CAPTIVE_OPTIONS_MODULE_TYPE_EMPTY:
161                         break;
162
163                 case CAPTIVE_OPTIONS_MODULE_TYPE_PE32:
164                         if (options_module->u.pe32.mapped)
165                                 captive_rtl_file_munmap(options_module->u.pe32.base);
166                         else
167                                 g_free(options_module->u.pe32.base);
168                         g_free(options_module->u.pe32.md5);
169                         break;
170
171                 case CAPTIVE_OPTIONS_MODULE_TYPE_GMODULE:
172                         g_free(options_module->u.gmodule.pathname);
173                         break;
174
175                 default: g_assert_not_reached();
176                 }
177 }