Adjust X11BASE so that ssh/sshd find xauth with pkgsrc.
[dragonfly.git] / sys / emulation / ndis / subr_pe.c
1 /*
2  * Copyright (c) 2003
3  *      Bill Paul <wpaul@windriver.com>.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by Bill Paul.
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30  * THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  * $DragonFly: src/sys/emulation/ndis/subr_pe.c,v 1.2 2005/12/10 16:06:20 swildner Exp $
33  * $FreeBSD: src/sys/compat/ndis/subr_pe.c,v 1.7 2004/01/13 22:49:45 obrien Exp $
34  */
35
36 /*
37  * This file contains routines for relocating and dynamically linking
38  * executable object code files in the Windows(r) PE (Portable Executable)
39  * format. In Windows, anything with a .EXE, .DLL or .SYS extention is
40  * considered an executable, and all such files have some structures in
41  * common. The PE format was apparently based largely on COFF but has
42  * mutated significantly over time. We are mainly concerned with .SYS files,
43  * so this module implements only enough routines to be able to parse the
44  * headers and sections of a .SYS object file and perform the necessary
45  * relocations and jump table patching to allow us to call into it
46  * (and to have it call back to us). Note that while this module
47  * can handle fixups for imported symbols, it knows nothing about
48  * exporting them.
49  */
50
51 #include <sys/param.h>
52 #include <sys/types.h>
53 #include <sys/errno.h>
54 #ifdef _KERNEL
55 #include <sys/systm.h>
56 #else
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <unistd.h>
60 #include <string.h>
61 #endif
62
63 #include "regcall.h"
64 #include "pe_var.h"
65
66 static vm_offset_t pe_functbl_match(image_patch_table *, char *);
67
68 /*
69  * Check for an MS-DOS executable header. All Windows binaries
70  * have a small MS-DOS executable prepended to them to print out
71  * the "This program requires Windows" message. Even .SYS files
72  * have this header, in spite of the fact that you're can't actually
73  * run them directly.
74  */
75
76 int
77 pe_get_dos_header(vm_offset_t imgbase, image_dos_header *hdr)
78 {
79         uint16_t                signature;
80
81         if (imgbase == 0 || hdr == NULL)
82                 return (EINVAL);
83
84         signature = *(uint16_t *)imgbase;
85         if (signature != IMAGE_DOS_SIGNATURE)
86                 return (ENOEXEC);
87
88         bcopy ((char *)imgbase, (char *)hdr, sizeof(image_dos_header));
89
90         return(0);
91 }
92
93 /*
94  * Verify that this image has a Windows NT PE signature.
95  */
96
97 int
98 pe_is_nt_image(vm_offset_t imgbase)
99 {
100         uint32_t                signature;
101         image_dos_header        *dos_hdr;
102
103         if (imgbase == 0)
104                 return (EINVAL);
105
106         signature = *(uint16_t *)imgbase;
107         if (signature == IMAGE_DOS_SIGNATURE) {
108                 dos_hdr = (image_dos_header *)imgbase;
109                 signature = *(uint32_t *)(imgbase + dos_hdr->idh_lfanew);
110                 if (signature == IMAGE_NT_SIGNATURE)
111                         return(0);
112         }
113
114         return(ENOEXEC);
115 }
116
117 /*
118  * Return a copy of the optional header. This contains the
119  * executable entry point and the directory listing which we
120  * need to find the relocations and imports later.
121  */
122
123 int
124 pe_get_optional_header(vm_offset_t imgbase, image_optional_header *hdr)
125 {
126         image_dos_header        *dos_hdr;
127         image_nt_header         *nt_hdr;
128
129         if (imgbase == 0 || hdr == NULL)
130                 return(EINVAL);
131
132         if (pe_is_nt_image(imgbase))
133                 return (EINVAL);
134
135         dos_hdr = (image_dos_header *)(imgbase);
136         nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
137
138         bcopy ((char *)&nt_hdr->inh_optionalhdr, (char *)hdr,
139             sizeof(image_optional_header));
140
141         return(0);
142 }
143
144 /*
145  * Return a copy of the file header. Contains the number of
146  * sections in this image.
147  */
148
149 int
150 pe_get_file_header(vm_offset_t imgbase, image_file_header *hdr)
151 {
152         image_dos_header        *dos_hdr;
153         image_nt_header         *nt_hdr;
154
155         if (imgbase == 0 || hdr == NULL)
156                 return(EINVAL);
157
158         if (pe_is_nt_image(imgbase))
159                 return (EINVAL);
160
161         dos_hdr = (image_dos_header *)imgbase;
162         nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
163
164         bcopy ((char *)&nt_hdr->inh_filehdr, (char *)hdr,
165             sizeof(image_file_header));
166
167         return(0);
168 }
169
170 /*
171  * Return the header of the first section in this image (usually
172  * .text).
173  */
174
175 int
176 pe_get_section_header(vm_offset_t imgbase, image_section_header *hdr)
177 {
178         image_dos_header        *dos_hdr;
179         image_nt_header         *nt_hdr;
180         image_section_header    *sect_hdr;
181
182         if (imgbase == 0 || hdr == NULL)
183                 return(EINVAL);
184
185         if (pe_is_nt_image(imgbase))
186                 return (EINVAL);
187
188         dos_hdr = (image_dos_header *)imgbase;
189         nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
190         sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr +
191             sizeof(image_nt_header));
192
193         bcopy ((char *)sect_hdr, (char *)hdr, sizeof(image_section_header));
194
195         return(0);
196 }
197
198 /*
199  * Return the number of sections in this executable, or 0 on error.
200  */
201
202 int
203 pe_numsections(vm_offset_t imgbase)
204 {
205         image_file_header       file_hdr;
206
207         if (pe_get_file_header(imgbase, &file_hdr))
208                 return(0);
209
210         return (file_hdr.ifh_numsections);
211 }
212
213 /*
214  * Return the base address that this image was linked for.
215  * This helps us calculate relocation addresses later.
216  */
217
218 vm_offset_t
219 pe_imagebase(vm_offset_t imgbase)
220 {
221         image_optional_header   optional_hdr;
222
223         if (pe_get_optional_header(imgbase, &optional_hdr))
224                 return(0);
225
226         return (optional_hdr.ioh_imagebase);
227 }
228
229 /*
230  * Return the offset of a given directory structure within the
231  * image. Directories reside within sections.
232  */
233
234 vm_offset_t
235 pe_directory_offset(vm_offset_t imgbase, uint32_t diridx)
236 {
237         image_optional_header   opt_hdr;
238         vm_offset_t             dir;
239
240         if (pe_get_optional_header(imgbase, &opt_hdr))
241                 return(0);
242
243         if (diridx >= opt_hdr.ioh_rva_size_cnt)
244                 return(0);
245
246         dir = opt_hdr.ioh_datadir[diridx].idd_vaddr;
247
248         return(pe_translate_addr(imgbase, dir));
249 }
250
251 vm_offset_t
252 pe_translate_addr(vm_offset_t imgbase, uint32_t rva)
253 {
254         image_optional_header   opt_hdr;
255         image_section_header    *sect_hdr;
256         image_dos_header        *dos_hdr;
257         image_nt_header         *nt_hdr;
258         int                     i = 0, sections, fixedlen;
259
260         if (pe_get_optional_header(imgbase, &opt_hdr))
261                 return(0);
262
263         sections = pe_numsections(imgbase);
264
265         dos_hdr = (image_dos_header *)imgbase;
266         nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
267         sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr +
268             sizeof(image_nt_header));
269
270         /*
271          * The test here is to see if the RVA falls somewhere
272          * inside the section, based on the section's start RVA
273          * and its length. However it seems sometimes the
274          * virtual length isn't enough to cover the entire
275          * area of the section. We fudge by taking into account
276          * the section alignment and rounding the section length
277          * up to a page boundary.
278          */
279         while (i++ < sections) {
280                 fixedlen = sect_hdr->ish_misc.ish_vsize;
281                 fixedlen += ((opt_hdr.ioh_sectalign - 1) -
282                     sect_hdr->ish_misc.ish_vsize) &
283                     (opt_hdr.ioh_sectalign - 1);
284                 if (sect_hdr->ish_vaddr <= (u_int32_t)rva &&
285                     (sect_hdr->ish_vaddr + fixedlen) >
286                     (u_int32_t)rva)
287                         break;
288                 sect_hdr++;
289         }
290
291         if (i > sections)
292                 return(0);
293
294         return((vm_offset_t)(imgbase + rva - sect_hdr->ish_vaddr +
295             sect_hdr->ish_rawdataaddr));
296 }
297
298 /*
299  * Get the section header for a particular section. Note that
300  * section names can be anything, but there are some standard
301  * ones (.text, .data, .rdata, .reloc).
302  */
303
304 int
305 pe_get_section(vm_offset_t imgbase, image_section_header *hdr,
306                const char *name)
307 {
308         image_dos_header        *dos_hdr;
309         image_nt_header         *nt_hdr;
310         image_section_header    *sect_hdr;
311
312         int                     i, sections;
313
314         if (imgbase == 0 || hdr == NULL)
315                 return(EINVAL);
316
317         if (pe_is_nt_image(imgbase))
318                 return (EINVAL);
319
320         sections = pe_numsections(imgbase);
321
322         dos_hdr = (image_dos_header *)imgbase;
323         nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
324         sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr +
325             sizeof(image_nt_header));
326
327         for (i = 0; i < sections; i++) {
328                 if (!strcmp ((char *)&sect_hdr->ish_name, name)) {
329                         bcopy((char *)sect_hdr, (char *)hdr,
330                             sizeof(image_section_header));
331                         return(0);
332                 } else
333                         sect_hdr++;
334         }
335
336         return (ENOEXEC);
337 }
338
339 /*
340  * Apply the base relocations to this image. The relocation table
341  * resides within the .reloc section. Relocations are specified in
342  * blocks which refer to a particular page. We apply the relocations
343  * one page block at a time.
344  */
345
346 int
347 pe_relocate(vm_offset_t imgbase)
348 {
349         image_section_header    sect;
350         image_base_reloc        *relhdr;
351         uint16_t                rel, *sloc;
352         uint32_t                base, delta, *lloc;
353         int                     i, count;
354         vm_offset_t             txt;
355
356         base = pe_imagebase(imgbase);
357         pe_get_section(imgbase, &sect, ".text");
358         txt = pe_translate_addr(imgbase, sect.ish_vaddr);
359         delta = (uint32_t)(txt) - base - sect.ish_vaddr;
360
361         pe_get_section(imgbase, &sect, ".reloc");
362
363         relhdr = (image_base_reloc *)(imgbase + sect.ish_rawdataaddr);
364
365         do {
366                 count = (relhdr->ibr_blocksize -
367                     (sizeof(uint32_t) * 2)) / sizeof(uint16_t);
368                 for (i = 0; i < count; i++) {
369                         rel = relhdr->ibr_rel[i];
370                         switch (IMR_RELTYPE(rel)) {
371                         case IMAGE_REL_BASED_ABSOLUTE:
372                                 break;
373                         case IMAGE_REL_BASED_HIGHLOW:
374                                 lloc = (uint32_t *)pe_translate_addr(imgbase,
375                                     relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
376                                 *lloc = pe_translate_addr(imgbase,
377                                     (*lloc - base));
378                                 break;
379                         case IMAGE_REL_BASED_HIGH:
380                                 sloc = (uint16_t *)pe_translate_addr(imgbase,
381                                     relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
382                                 *sloc += (delta & 0xFFFF0000) >> 16;
383                                 break;
384                         case IMAGE_REL_BASED_LOW:
385                                 sloc = (uint16_t *)pe_translate_addr(imgbase,
386                                     relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
387                                 *sloc += (delta & 0xFFFF);
388                                 break;
389                         default:
390                                 printf ("[%d]reloc type: %d\n",i,
391                                     IMR_RELTYPE(rel));
392                                 break;
393                         }
394                 }
395                 relhdr = (image_base_reloc *)((vm_offset_t)relhdr +
396                     relhdr->ibr_blocksize);
397         } while (relhdr->ibr_blocksize);
398
399         return(0);
400 }
401
402 /*
403  * Return the import descriptor for a particular module. An image
404  * may be linked against several modules, typically HAL.dll, ntoskrnl.exe
405  * and NDIS.SYS. For each module, there is a list of imported function
406  * names and their addresses.
407  */
408
409 int
410 pe_get_import_descriptor(vm_offset_t imgbase, image_import_descriptor *desc,
411                          char *module)
412 {       
413         vm_offset_t             offset;
414         image_import_descriptor *imp_desc;
415         char                    *modname;
416
417         if (imgbase == 0 || module == NULL || desc == NULL)
418                 return(EINVAL);
419
420         offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_IMPORT);
421         if (offset == 0)
422                 return (ENOENT);
423
424         imp_desc = (void *)offset;
425
426         while (imp_desc->iid_nameaddr) {
427                 modname = (char *)pe_translate_addr(imgbase,
428                     imp_desc->iid_nameaddr);
429                 if (!strncmp(module, modname, strlen(module))) {
430                         bcopy((char *)imp_desc, (char *)desc,
431                             sizeof(image_import_descriptor));
432                         return(0);
433                 }
434                 imp_desc++;
435         }
436
437         return (ENOENT);
438 }
439
440 int
441 pe_get_messagetable(vm_offset_t imgbase, message_resource_data **md)
442 {
443         image_resource_directory        *rdir, *rtype;
444         image_resource_directory_entry  *dent, *dent2;
445         image_resource_data_entry       *rent;
446         vm_offset_t             offset;
447         int                     i;
448
449         if (imgbase == 0)
450                 return(EINVAL);
451
452         offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_RESOURCE);
453         if (offset == 0)
454                 return (ENOENT);
455
456         rdir = (image_resource_directory *)offset;
457
458         dent = (image_resource_directory_entry *)(offset +
459             sizeof(image_resource_directory));
460
461         for (i = 0; i < rdir->ird_id_entries; i++){
462                 if (dent->irde_name != RT_MESSAGETABLE) {
463                         dent++;
464                         continue;
465                 }
466                 dent2 = dent;
467                 while (dent2->irde_dataoff & RESOURCE_DIR_FLAG) {
468                         rtype = (image_resource_directory *)(offset +
469                             (dent2->irde_dataoff & ~RESOURCE_DIR_FLAG));
470                         dent2 = (image_resource_directory_entry *)
471                             ((uintptr_t)rtype +
472                              sizeof(image_resource_directory));
473                 }
474                 rent = (image_resource_data_entry *)(offset +
475                     dent2->irde_dataoff);
476                 *md = (message_resource_data *)pe_translate_addr(imgbase,
477                     rent->irde_offset);
478                 return(0);
479         }
480
481         return(ENOENT);
482 }
483
484 int
485 pe_get_message(vm_offset_t imgbase, uint32_t id, char **str, int *len,
486                uint16_t *flags)
487 {
488         message_resource_data   *md = NULL;
489         message_resource_block  *mb;
490         message_resource_entry  *me;
491         uint32_t                i;
492
493         pe_get_messagetable(imgbase, &md);
494
495         if (md == NULL)
496                 return(ENOENT);
497
498         mb = (message_resource_block *)((uintptr_t)md +
499             sizeof(message_resource_data));
500
501         for (i = 0; i < md->mrd_numblocks; i++) {
502                 if (id >= mb->mrb_lowid && id <= mb->mrb_highid) {
503                         me = (message_resource_entry *)((uintptr_t)md +
504                             mb->mrb_entryoff);
505                         for (i = id - mb->mrb_lowid; i > 0; i--)
506                                 me = (message_resource_entry *)((uintptr_t)me +
507                                     me->mre_len);
508                         *str = me->mre_text;
509                         *len = me->mre_len;
510                         *flags = me->mre_flags;
511                         return(0);
512                 }
513                 mb++;
514         }
515
516         return(ENOENT);
517 }
518
519 /*
520  * Find the function that matches a particular name. This doesn't
521  * need to be particularly speedy since it's only run when loading
522  * a module for the first time.
523  */
524
525 static vm_offset_t
526 pe_functbl_match(image_patch_table *functbl, char *name)
527 {
528         image_patch_table       *p;
529
530         if (functbl == NULL || name == NULL)
531                 return(0);
532
533         p = functbl;
534
535         while (p->ipt_name != NULL) {
536                 if (!strcmp(p->ipt_name, name))
537                         return((vm_offset_t)p->ipt_func);
538                 p++;
539         }
540         printf ("no match for %s\n", name);
541         return((vm_offset_t)p->ipt_func);
542 }
543
544 /*
545  * Patch the imported function addresses for a given module.
546  * The caller must specify the module name and provide a table
547  * of function pointers that will be patched into the jump table.
548  * Note that there are actually two copies of the jump table: one
549  * copy is left alone. In a .SYS file, the jump tables are usually
550  * merged into the INIT segment.
551  */
552
553 int
554 pe_patch_imports(vm_offset_t imgbase, char *module,
555                  image_patch_table *functbl)
556 {
557         image_import_descriptor imp_desc;
558         char                    *fname;
559         vm_offset_t             *nptr, *fptr;
560         vm_offset_t             func;
561
562         if (imgbase == 0 || module == NULL || functbl == NULL)
563                 return(EINVAL);
564
565         if (pe_get_import_descriptor(imgbase, &imp_desc, module))
566                 return(ENOEXEC);
567
568         nptr = (vm_offset_t *)pe_translate_addr(imgbase,
569             imp_desc.iid_import_name_table_addr);
570         fptr = (vm_offset_t *)pe_translate_addr(imgbase,
571             imp_desc.iid_import_address_table_addr);
572
573         while (nptr != NULL && pe_translate_addr(imgbase, *nptr)) {
574                 fname = (char *)pe_translate_addr(imgbase, (*nptr) + 2);
575                 func = pe_functbl_match(functbl, fname);
576                 if (func)
577                         *fptr = func;
578 #ifdef notdef
579                 if (*fptr == 0)
580                         return(ENOENT);
581 #endif
582                 nptr++;
583                 fptr++;
584         }
585
586         return(0);
587 }