OSDN Git Service

6d2396ee30505a4b5ec225443cacff61354e6ebc
[openpts/openpts.git] / src / smbios.c
1 /*
2  * This file is part of the OpenPTS project.
3  *
4  * The Initial Developer of the Original Code is International
5  * Business Machines Corporation. Portions created by IBM
6  * Corporation are Copyright (C) 2010 International Business
7  * Machines Corporation. All Rights Reserved.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the Common Public License as published by
11  * IBM Corporation; either version 1 of the License, or (at your option)
12  * any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * Common Public License for more details.
18  *
19  * You should have received a copy of the Common Public License
20  * along with this program; if not, a copy can be viewed at
21  * http://www.opensource.org/licenses/cpl1.0.php.
22  */
23
24 /**
25  * \file src/smbios.c
26  * \brief parse SMBIOS info
27  * @author Seiji Munetoh <munetoh@users.sourceforge.jp>
28  * @date 2010-08-29
29  * cleanup 2011-01-22 SM
30  *
31  * SMBIOS Info in BIOS IML -> platform properties
32  *
33  * TODO not work yet:-(
34  *      SMBIOS info in the IML has been masked.
35  *      It masks sensitive information in the SMBIOS data blob.
36  *      However this makes hard to parse the ASN.1 structure.
37  */
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <netdb.h>
43 #include <errno.h>
44
45 #include <sys/types.h>
46 #include <sys/socket.h>
47 #include <sys/stat.h>
48 #include <netinet/in.h>
49 #include <fcntl.h>
50
51 #include <unistd.h>
52 #include <sys/wait.h>
53 #include <dirent.h>
54
55 #include <openpts.h>
56 // #include <log.h>
57
58 #define SMBIOS_MAX_SIZE   4096
59 #define SMBIOS_MAX_HANDLE 0x50
60 #define DMIDECODE_PATH    "/usr/sbin/dmidecode"
61 #define DMIDECODE         "dmidecode"
62
63 /**
64  * dmidecode --dump-bin dmidecode.bin
65  */
66 int genSmbiosFileByDmidecode(char * filename) {
67     pid_t pid;
68     int status;
69     int uid;
70
71     /* must be a root user */
72     uid = getuid();
73     // DEBUG("UID %d\n",uid);
74     if (uid != 0) {
75         DEBUG("must be a root user to run dmidecode\n");
76         return -2;
77     }
78
79     /* exec dmidecode */
80     pid = fork();
81     if (pid < 0) {
82         ERROR("\n");
83         return -1;
84     }
85     if (pid == 0) {
86         /* child */
87         execl(DMIDECODE_PATH, DMIDECODE, "--dump-bin", filename,  NULL);
88
89         /* execl failed */
90         exit(-1);
91     } else {
92         /* parent */
93         waitpid(pid, &status, 0);
94         // DEBUG("status = %d\n", status);
95         if (WIFEXITED(status)) {
96             /* 1 : OK */
97             TODO("Exit status %d\n", WEXITSTATUS(status));
98             return 1;
99         } else if (WIFSIGNALED(status)) {
100             ERROR("Signal status %d\n", WIFSIGNALED(status));
101             return -1;
102         } else {
103             ERROR("Bad exit");
104             return -1;
105         }
106     }
107
108     return 0;
109 }
110
111
112 /**
113  * read SMBIOS File
114  * 
115  *  dmidecode --dump-bin dmidecode.bin
116  *
117  * SMBIOS data -> malloc -> data
118  * 
119  */
120 int readSmbiosFile(char * filename, BYTE **data, int *len) {
121     FILE *fp;
122     int size;
123     BYTE *buf;
124     int rc = PTS_SUCCESS;
125
126     buf = xmalloc(SMBIOS_MAX_SIZE);  // TODO check the filesize
127     if (buf == NULL) {
128         return PTS_FATAL;
129     }
130
131     if ((fp = fopen(filename, "rb")) == NULL) {
132         ERROR("%s missing\n", filename);
133         rc = PTS_INTERNAL_ERROR;
134         goto error;
135     }
136
137     size = fread(buf, 1, SMBIOS_MAX_SIZE, fp);  // TODO(munetoh) check the file size
138
139     fclose(fp);
140
141     *len = size;
142     *data = buf;
143     return rc;
144
145   error:
146     xfree(buf);
147     return rc;
148 }
149
150 /**
151  * print SMBIOS info
152  *
153  * http://en.wikipedia.org/wiki/System_Management_BIOS
154  * http://dmtf.org/standards/smbios
155  *
156  * Lenovo - sensitive data of SMBIOS in IML is masked 
157  */
158 int printSmbios(BYTE *data, int length) {
159     BYTE type;
160     BYTE len;
161     int handle;
162     int handle_old = -1;
163     BYTE *ptr = data;
164     BYTE *strings;
165     BYTE *eod = data + length;
166     int str_length;
167     int str_num;
168     int cnt = 0;
169
170     if ((ptr[0] == 0x5f) && (ptr[1] == 0x53) && (ptr[2] == 0x4d) && (ptr[3] == 0x5f)) {
171         /* */
172         str_length = ptr[0x16] + (ptr[0x17]<<8);
173         str_num = ptr[0x1C] + (ptr[0x1D]<<8);
174         printf(NLS(MS_OPENPTS, OPENPTS_SMBIOS_STRUCTURES,
175             "%d structures occupying %d bytes.\n"), str_num, str_length);
176         eod = ptr + str_length + 32;
177         // SKIP Head
178         ptr += 32;
179     }
180
181
182
183     while (1) {
184         type = ptr[0];
185         len = ptr[1];
186         handle = ptr[2] + ptr[3]*256;
187         printf(NLS(MS_OPENPTS, OPENPTS_SMBIOS_HANDLE,
188             "Handle 0x%04x, DMI type %d(0x%x), %d bytes\n"), handle, type, type, len);
189         printHex(NLS(MS_OPENPTS, OPENPTS_SMBIOS_HEAD, "  head"), ptr, len, "\n");
190
191         if (type == 127) {
192             printf(NLS(MS_OPENPTS, OPENPTS_SMBIOS_END_OF_TABLE, "End Of Table\n"));
193             // printf("%ld\n", ptr - data);
194             break;
195         }
196
197         ptr += len;
198         strings = ptr;
199
200         if (handle != handle_old +1) {
201             break;
202         }
203
204         if (ptr >  eod) {
205             printf(NLS(MS_OPENPTS, OPENPTS_SMBIOS_END_OF_TABLE, "End Of Table\n"));
206             break;
207         }
208
209         /* skip zero*/
210         while (!((*ptr == 0) && (*(ptr+1) == 0) && (*(ptr + 2) != 0))) {
211             ptr++;
212             if (ptr > eod) {
213                 break;
214             }
215         }
216         ptr++;
217         ptr++;
218
219         printHex(NLS(MS_OPENPTS, OPENPTS_SMBIOS_BODY, "  body"), strings, ptr - strings, "\n");
220
221
222         if (ptr > eod) {
223             break;
224         }
225
226         cnt++;
227         if (cnt > SMBIOS_MAX_HANDLE) {
228             break;
229         }
230
231         handle_old = handle;
232     }
233
234     return 0;
235 }
236
237
238
239 #define SMBIOS_MAX_HANDLE 0x50
240 /**
241  * SMBIOS -> properties 
242  *
243  * IR:core:ComponentID  < Core Integrity Schema 3.1.2
244  * ---------------------------------------
245  * Id
246  * SimpleName           BIOS
247  * ModelName          
248  * ModelNumber          
249  * ModelSerialNumber
250  * ModelSystemClass
251  * VersionMajor         bios.version.major=3
252  * VersionMinor         bios.version.minor=8
253  * VersionBuild         bios.date=08/20/2009
254  * VersionString        bios.version=6DET58WW (3.08 )
255  * MfgData
256  * PatchLevel
257  * DiscreatePatches
258  * ----------------------------------------
259  * IR:core:VendorID
260  * ---------------------------------------
261  * Name                 bios.vendor.name=LENOVO
262  *
263  * IR:core:SmiVendorID  bios.vendor.smi=19046 << IANA.ORG
264  * ---------------------------------------
265  *
266  * # => PTS_ComponentId
267  *
268  */
269 int parseSmbios(OPENPTS_CONTEXT *ctx, BYTE *data, int length) {
270     BYTE type;
271     BYTE len;
272     int handle;
273     int handle_old = -1;
274     BYTE *ptr = data;
275     BYTE *strings[10];  // TODO size
276     BYTE *eod = data + length;
277     int str_length;
278     // int str_num;
279     int cnt = 0;
280     int scnt;
281     OPENPTS_CONFIG *conf = ctx->conf;
282
283     /* skip header */
284     if ((ptr[0] == 0x5f) && (ptr[1] == 0x53) && (ptr[2] == 0x4d) && (ptr[3] == 0x5f)) {
285         /* */
286         str_length = ptr[0x16] + (ptr[0x17]<<8);
287         // str_num = ptr[0x1C] + (ptr[0x1D]<<8);
288         // printf("%d structures occupying %d bytes.\n", str_num, str_length);
289         eod = ptr + str_length + 32;
290         // SKIP Head
291         ptr += 32;
292     }
293
294     /* initialize */
295     strings[0] = NULL;
296     strings[1] = NULL;
297
298     /* walk on structures */
299     while (1) {
300         type = ptr[0];
301         len = ptr[1];
302         handle = ptr[2] + ptr[3]*256;
303         // printf("Handle 0x%04x, DMI type %d(0x%x), %d bytes\n", handle, type,type, len);
304         // printHex("  head",ptr, len, "\n");
305
306         if (type == 127) {
307             // printf("End Of Table\n");
308             // printf("%ld\n", ptr - data);
309             break;
310         }
311
312         ptr += len;
313         strings[0] = ptr;
314         scnt = 0;
315
316         if (handle != handle_old +1) {
317             break;
318         }
319
320         if (ptr >  eod) {
321             // printf("End Of Table\n");
322             break;
323         }
324
325         /* skip zero*/
326         while (!((*ptr == 0) && (*(ptr+1) == 0) && (*(ptr + 2) != 0))) {
327             ptr++;
328             if (ptr > eod) {
329                 break;
330             }
331             if ((*ptr != 0) && (*(ptr+1) == 0)) {
332                 scnt++;  // TODO check max
333                 strings[scnt] = ptr + 2;
334             }
335         }
336         ptr++;
337         ptr++;
338
339         // printHex("  body", strings[0], ptr - strings[0], "\n");
340         // printf("  scnt %d\n",scnt);
341         // for (i=0;i<scnt;i++) {
342         //     printf("    %d %s\n",i, strings[i]);
343         // }
344
345         /* to config  */
346         switch (type) {
347             case 0x0: /* BIOS Information */
348                 conf->bios_vendor = smalloc_assert((char*)strings[0]);
349                 conf->bios_version = smalloc_assert((char*)strings[1]);
350                 break;
351             default:
352                 break;
353         }
354
355
356         if (ptr > eod) {
357             break;
358         }
359
360         cnt++;
361         if (cnt > SMBIOS_MAX_HANDLE) {
362             break;
363         }
364
365         handle_old = handle;
366     }
367
368     return 0;
369 }