FOSSology  3.2.0rc1
Open Source License Compliance by Open Source Software
ununpack-disk.c
Go to the documentation of this file.
1 /*******************************************************************
2  Copyright (C) 2007-2011 Hewlett-Packard Development Company, L.P.
3 
4  This program is free software; you can redistribute it and/or
5  modify it under the terms of the GNU General Public License
6  version 2 as published by the Free Software Foundation.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License 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  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16  *******************************************************************/
17 
23 #include "ununpack.h"
24 #include "externs.h"
25 
26 #include <utime.h>
27 
31 struct permlist
32 {
33  char *inode;
34  struct utimbuf Times;
35  int perm;
36  struct permlist *Next;
37 };
38 typedef struct permlist permlist;
39 
40 
48 void FatDiskName (char *Name)
49 {
50  int i;
51 
52  for(i=0; Name[i] != '\0'; i++)
53  {
54  if (isupper(Name[i])) Name[i]=tolower(Name[i]);
55  }
56  /* i == strlen(Name) */
57  if (i <= 0) return;
58  i--;
59  if (Name[i] != ')') return; /* no paren name! */
60  /* remove the parenthasis name */
61  while((i>1) && (Name[i] != '(')) i--;
62  if (Name[i]=='(')
63  {
64  i--;
65  if (Name[i]==' ') Name[i]='\0';
66  }
67 } /* FatDiskName() */
68 
73 void FreeDiskPerms (permlist *List)
74 {
75  permlist *Next;
76  while(List)
77  {
78  Next=List->Next;
79  if (List->inode) free(List->inode);
80  free(List);
81  List=Next;
82  }
83 } /* FreeDiskPerms() */
84 
92 permlist * ExtractDiskPerms (char *FStype, char *Source)
93 {
94  permlist *List=NULL, *NewList;
95  FILE *Fin;
96  char Cmd[FILENAME_MAX*2]; /* command to run */
97  char Line[FILENAME_MAX*2];
98  char *L; /* pointer into Line */
99  char *inode;
100 
101  /* Format of "fls -m /" (as determined from the fls source code fs_dent.c):
102  0|/etc/terminfo/b/bterm|0|95|33188|-/-rw-r--r--|1|0|0|0|1204|1128185330|1128185330|1128185330|1024|0
103  0 = always zero (may become md5 some day, but fls does not do it yet)
104  /etc/terminfo/b/bterm = filename relative to "-m /"
105  -- filename may contain ":stream" for NTFS streams
106  -- filename may contain "-> filename" for symbolic links
107  -- filename may contain "(deleted...)" (e.g., deleted-realloc)
108  0 = always zero (may change in the future
109  95 = inode (treat as string)
110  33188 = numeric (decimal) of permissions
111  -/-rw-r--r-- = text of permissions
112  1 = number of hard links
113  0 = uid
114  0 = gid
115  0 = always zero
116  1204 = file size (bytes)
117  1128185330 = atime
118  1128185330 = mtime
119  1128185330 = ctime
120  1024 = block size
121  0 = always zero
122  */
123 
124  snprintf(Cmd,sizeof(Cmd),"fls -m / -f '%s' -lpr '%s' 2>/dev/null",
125  FStype,Source);
126  Fin = popen(Cmd,"r");
127  if (!Fin)
128  {
129  fprintf(stderr,"ERROR: Disk failed: %s\n",Cmd);
130  return(NULL);
131  }
132 
133  while(ReadLine(Fin,Line,sizeof(Line)-1) >= 0)
134  {
135  NewList = (permlist *)malloc(sizeof(permlist));
136  if (!NewList)
137  {
138  printf("FATAL: Unable to allocated %d bytes of memory\n",(int)sizeof(permlist));
139  SafeExit(-1);
140  }
141  NewList->inode = NULL;
142  NewList->Next = NULL;
143  L=Line;
144  L=strchr(L,'|'); if (!L) {FreeDiskPerms(NewList); continue;} L++; /* name */
145  /* skip any realloc'ed names (deleted is fine...) */
146  if (strstr(L,"realloc)|")) {FreeDiskPerms(NewList); continue;}
147  L=strchr(L,'|'); if (!L) {FreeDiskPerms(NewList); continue;} L++; /* zero */
148  L=strchr(L,'|'); if (!L) {FreeDiskPerms(NewList); continue;} L++; /* inode */
149  inode = L; /* start of inode, but not length */
150  L=strchr(L,'|'); if (!L) {FreeDiskPerms(NewList); continue;} L++; /* perm */
151  NewList->perm = atoi(L);
152  /* now save inode string info */
153  if (L <= inode) {FreeDiskPerms(NewList); continue;}
154  NewList->inode = (char *)calloc(L-inode,1);
155  if (!NewList->inode)
156  {
157  printf("FATAL: Unable to allocate %d bytes.\n",(int)(L-inode));
158  SafeExit(-1);
159  }
160  memcpy(NewList->inode,inode,L-inode-1);
161 
162  L=strchr(L,'|'); if (!L) {FreeDiskPerms(NewList); continue;} L++; /* perm text */
163  L=strchr(L,'|'); if (!L) {FreeDiskPerms(NewList); continue;} L++; /* hard links */
164  L=strchr(L,'|'); if (!L) {FreeDiskPerms(NewList); continue;} L++; /* uid */
165  L=strchr(L,'|'); if (!L) {FreeDiskPerms(NewList); continue;} L++; /* gid */
166  L=strchr(L,'|'); if (!L) {FreeDiskPerms(NewList); continue;} L++; /* zero */
167  L=strchr(L,'|'); if (!L) {FreeDiskPerms(NewList); continue;} L++; /* file size */
168  L=strchr(L,'|'); if (!L) {FreeDiskPerms(NewList); continue;} L++; /* atime */
169  NewList->Times.actime = atoi(L);
170  L=strchr(L,'|'); if (!L) {FreeDiskPerms(NewList); continue;} L++; /* mtime */
171  NewList->Times.modtime = atoi(L);
172  /* NOTE: No way to set ctime! */
173  /* save item */
174  NewList->Next = List;
175  List = NewList;
176  } /* while read line */
177  pclose(Fin);
178  return(List);
179 } /* ExtractDiskPerms() */
180 
189 int SameInode (char *Inode1, char *Inode2)
190 {
191  int i;
192  int v1,v2;
193  for(i=0; Inode1[i] && Inode2[i]; i++)
194  {
195  if (isdigit(Inode1[i]) || (Inode1[i]=='-'))
196  {
197  if (Inode1[i] != Inode2[i]) return(0);
198  }
199  else break; /* out of the loop */
200  }
201  /* ok, they differ... */
202  v1 = (isdigit(Inode1[i]) || (Inode1[i]=='-'));
203  v2 = (isdigit(Inode2[i]) || (Inode2[i]=='-'));
204  return(v1==v2); /* if they are both end-of-inode, then ok! */
205 } /* SameInode() */
206 
216 permlist * SetDiskPerm (char *inode, permlist *List,
217  char *Destination, char *Target)
218 {
219  permlist *NewList, *Parent;
220  char *Cwd;
221 
222  /* base case */
223  if (!List) return(NULL);
224 
225  /* inodes could start with a non-digit */
226  while((inode[0] != '\0') && !isdigit(inode[0])) inode++;
227 
228  /* base case */
229  if (SameInode(List->inode,inode)) goto FoundPerm;
230 
231  /* else, find the list */
232  Parent = List;
233  while(Parent->Next)
234  {
235  if (SameInode(Parent->Next->inode,inode))
236  {
237  /* re-order so desired element is head of list */
238  NewList = Parent->Next; /* hold matching element */
239  Parent->Next = NewList->Next; /* bypass matching element */
240  NewList->Next = List; /* move element to start of list */
241  List = NewList; /* reset start of list */
242  goto FoundPerm;
243  }
244  Parent = Parent->Next;
245  }
246  if (Verbose) fprintf(stderr,"LOG pfile %s WARNING Could not find inode: %s\n",Pfile,inode);
247  return(List); /* don't change list */
248 
249  FoundPerm:
250  Cwd = getcwd(NULL,0);
251  if (!Cwd)
252  {
253  printf("ERROR: Current directory no longer exists! Aborting!\n");
254  SafeExit(-1); /* this never returns */
255  }
256 
257  if(chdir(Destination) != 0)
258  {
259  fprintf(stderr, "ERROR %s.%d: Unable to change directory to %s\n",
260  __FILE__, __LINE__, Destination);
261  fprintf(stderr, "ERROR: errno is: %s\n", strerror(errno));
262  }
263 
264  if (Verbose > 1) fprintf(stderr,"DEBUG: setting inode %s, name %s to %07o\n",List->inode,Target,List->perm);
265  chmod(Target,List->perm); /* allow suid */
266  utime(Target,&(List->Times));
267 
268  if(chdir(Cwd) != 0)
269  {
270  fprintf(stderr, "ERROR %s.%d: Unable to change directory to %s\n",
271  __FILE__, __LINE__, Cwd);
272  fprintf(stderr, "ERROR: errno is: %s\n", strerror(errno));
273  }
274 
275  free(Cwd);
276  Parent = List->Next;
277  List->Next=NULL;
278  FreeDiskPerms(List);
279  return(Parent);
280 } /* SetDiskPerm() */
281 
299 int ExtractDisk (char *Source, char *FStype, char *Destination)
300 {
301  int rc;
302  char Cmd[FILENAME_MAX*7]; /* command to run */
303  char Line[FILENAME_MAX*2];
304  char *s;
305  FILE *Fin;
306  int FatFlag=0;
307  char *Inode,I;
308  int InodeLen;
309  /* for tainting strings in commands */
310  char TempSource[FILENAME_MAX];
311  char TempInode[FILENAME_MAX], TempDest[FILENAME_MAX], TempS[FILENAME_MAX];
312  permlist *Perms;
313 
314  /* judge if the parameters are empty */
315  if ((NULL == FStype) || (!strcmp(FStype, "")) || (NULL == Source) || (!strcmp(Source, "")) || (NULL == Destination) || (!strcmp(Destination, "")))
316  return 1;
317 
318  if (!Quiet && Verbose) fprintf(stderr,"Extracting %s: %s\n",FStype,Source);
319 
320  if (!strcmp(FStype,"fat")) FatFlag=1;
321 
322  /* get list of directories to extract to */
323  /* NOTE: There is no distinction between real and deleted directories */
324  /* CMD: fls -f 'FStype' -Dpr 'Source' */
325  if (TaintString(TempSource,FILENAME_MAX,Source,1,NULL))
326  return(-1);
327  snprintf(Cmd,sizeof(Cmd),"fls -f '%s' -Dpr '%s' 2>&1",FStype,TempSource);
328  Fin = popen(Cmd,"r");
329  if (!Fin)
330  {
331  fprintf(stderr,"ERROR: Disk failed: %s\n",Cmd);
332  return(-1);
333  }
334  while(ReadLine(Fin,Line,sizeof(Line)-1) >= 0)
335  {
336  /* check for errors */
337  if (!memcmp(Line,"fls: ",5))
338  {
339  fprintf(stderr,"WARNING pfile %s Unable to extract\n",Pfile);
340  fprintf(stderr,"LOG pfile %s WARNING: fls extraction issue on '%s'. %s\n",
341  Pfile,TempSource,Line);
342  }
343  /* line should start "d/d" */
344  /* other line types: "l/d" */
345  if (memcmp(Line,"d/d",3) != 0) continue; /* line should start "d/d" */
346  if (strstr(Line," (deleted-realloc)") != NULL) continue; /* skip reallocs */
347  if (FatFlag) FatDiskName(Line);
348  s=strchr(Line,'\t'); /* filename starts at tab */
349  if (s==NULL) continue; /* there can be blank lines */
350  s++;
351  snprintf(Cmd,sizeof(Cmd),"%s/%s",Destination,s);
352  if (MkDir(Cmd))
353  {
354  printf("ERROR: Unable to mkdir(%s) in ExtractDisk\n",Cmd);
355  if (!ForceContinue) SafeExit(-1);
356  }
357  }
358  pclose(Fin);
359 
360  /* Get disk permissions */
361  /* NOTE: Do this AFTER making directories because:
362  (1) We know extraction will work.
363  (2) If we chmod before extraction then directory may not allow writing
364  NOTE: Permissions on NTFS file systems looks broken in fls!
365  */
366  {
367  Perms = ExtractDiskPerms(FStype,TempSource);
368  if (!Perms)
369  {
370  fprintf(stderr,"WARNING pfile %s Unable to extract permission\n",Pfile);
371  fprintf(stderr,"LOG pfile %s WARNING: Unable to extract permission from %s\n",Pfile,Source);
372  }
373  }
374 
375  /* get list of regular (not deleted) files to extract */
376  /* CMD: fls -f 'FStype' -Fupr 'Source' */
377  snprintf(Cmd,sizeof(Cmd),"fls -f '%s' -Fupr '%s' 2>/dev/null",FStype,TempSource);
378  Fin = popen(Cmd,"r");
379  if (!Fin)
380  {
381  fprintf(stderr,"ERROR: Disk failed: %s\n",Cmd);
382  FreeDiskPerms(Perms);
383  return(-1);
384  }
385  while(ReadLine(Fin,Line,sizeof(Line)-1) >= 0)
386  {
387  if (FatFlag) FatDiskName(Line);
388  /* Sample line: "r/r 95: etc/terminfo/b/bterm" */
389  /* only handle regular files */
390  if (memcmp(Line,"r/r",3) != 0) continue; /* line should start "r/r" */
391  s=strchr(Line,'\t'); /* filename starts after tab */
392  if (s==NULL) continue; /* there could be blank lines */
393  s++;
394  /* Under unix, inodes are numbers. Under ntfs, it can be a string */
395  Inode = Line+4; /* should be a number ended with a colon */
396  InodeLen=0;
397  while(Inode[InodeLen] && (Inode[InodeLen] != ':'))
398  {
399  InodeLen++;
400  }
401 
402  /* CMD: icat -f 'FStype' 'Source' 'Inode' > 'Destination/s' */
403  I=Inode[InodeLen];
404  Inode[InodeLen]='\0';
405  if (TaintString(TempInode,FILENAME_MAX,Inode,1,NULL) ||
406  TaintString(TempDest,FILENAME_MAX,Destination,1,NULL) ||
407  TaintString(TempS,FILENAME_MAX,s,1,NULL))
408  {
409  Inode[InodeLen]=I;
410  FreeDiskPerms(Perms);
411  return(-1);
412  }
413  Inode[InodeLen]=I;
414  if (Verbose) printf("Extracting: icat '%s/%s'\n",TempDest,TempS);
415  snprintf(Cmd,sizeof(Cmd),"icat -f '%s' '%s' '%s' > '%s/%s' 2>/dev/null",
416  FStype,TempSource,TempInode,TempDest,TempS);
417 
418  rc = system(Cmd);
419  if (WIFSIGNALED(rc))
420  {
421  printf("ERROR: Process killed by signal (%d): %s\n",WTERMSIG(rc),Cmd);
422  SafeExit(-1);
423  }
424  rc = WEXITSTATUS(rc);
425  if (rc)
426  {
427  fprintf(stderr,"WARNING pfile %s File extraction failed\n",Pfile);
428  fprintf(stderr,"LOG pfile %s WARNING: Extraction failed (rc=%d): %s\n",Pfile,rc,Cmd);
429  }
430 
431  /* set file permissions */
432  Perms = SetDiskPerm(Inode,Perms,Destination,s);
433  } /* while read Line */
434  pclose(Fin);
435 
436  /* get list of DELETED files to extract (fls -d means deleted) */
437  /* CMD: fls -f 'FStype' -Fdpr 'Source' */
438  snprintf(Cmd,sizeof(Cmd),"fls -f '%s' -Fdpr '%s' 2>/dev/null",FStype,TempSource);
439  Fin = popen(Cmd,"r");
440  if (!Fin)
441  {
442  fprintf(stderr,"ERROR: Disk failed: %s\n",Cmd);
443  FreeDiskPerms(Perms);
444  return(-1);
445  }
446  while(ReadLine(Fin,Line,sizeof(Line)-1) >= 0)
447  {
448  if (FatFlag) FatDiskName(Line);
449  /* Sample line: "r/r 95: etc/terminfo/b/bterm" */
450  /* only handle regular files */
451  if (memcmp(Line,"r/r",3) != 0) continue; /* line should start "r/r" */
452  s=strchr(Line,'\t'); /* filename starts after tab */
453  if (s==NULL) continue; /* there could be blank lines */
454  s++;
455  Inode = Line+6; /* should be "* number:" or "* number(realloc)" */
456  InodeLen=0;
457  while(Inode[InodeLen] && !strchr(":(",Inode[InodeLen]))
458  {
459  InodeLen++;
460  }
461  if (Inode[InodeLen] =='(') continue; /* skip reallocs */
462  /* The same file may exist multiple times (lots of deletes).
463  For uniqueness, the inode number is included.
464  NOTE: "realloc" means the inode was reallocated! */
465  /* CMD: icat -f 'FStype' 'Source' 'Inode' > 'Destination/s.deleted.Inode' */
466  I=Inode[InodeLen];
467  Inode[InodeLen]='\0';
468  if (TaintString(TempInode,FILENAME_MAX,Inode,1,NULL) ||
469  TaintString(TempDest,FILENAME_MAX,Destination,1,NULL) ||
470  TaintString(TempS,FILENAME_MAX,s,1,NULL))
471  {
472  Inode[InodeLen]=I;
473  FreeDiskPerms(Perms);
474  return(-1);
475  }
476  Inode[InodeLen]=I;
477  snprintf(Cmd,sizeof(Cmd),"icat -f '%s' '%s' '%s' > '%s/%s.deleted.%s' 2>/dev/null",
478  FStype,TempSource,TempInode,TempDest,TempS,TempInode);
479 
480  if (Verbose) printf("Extracting: icat '%s/%s'\n",TempDest,TempS);
481  rc = system(Cmd);
482  if (WIFSIGNALED(rc))
483  {
484  printf("ERROR: Process killed by signal (%d): %s\n",WTERMSIG(rc),Cmd);
485  SafeExit(-1);
486  }
487  rc = WEXITSTATUS(rc);
488  if (rc)
489  {
490  fprintf(stderr,"WARNING pfile %s File extraction failed\n",Pfile);
491  fprintf(stderr,"LOG pfile %s WARNING: Extraction failed (rc=%d): %s\n",Pfile,rc,Cmd);
492  }
493 
494  /* set file permissions */
495  Perms = SetDiskPerm(Inode,Perms,Destination,s);
496  } /* while read line */
497  pclose(Fin);
498 
499  /* for completeness, put back directory permissions */
500  snprintf(Cmd,sizeof(Cmd),"fls -f '%s' -Dpr '%s' 2>/dev/null",FStype,TempSource);
501  Fin = popen(Cmd,"r");
502  if (!Fin)
503  {
504  fprintf(stderr,"ERROR: Disk failed: %s\n",Cmd);
505  return(-1);
506  }
507  while(ReadLine(Fin,Line,sizeof(Line)-1) >= 0)
508  {
509  if (memcmp(Line,"d/d",3) != 0) continue; /* line should start "d/d" */
510  if (FatFlag) FatDiskName(Line);
511  Inode = Line+4;
512  s=strchr(Line,'\t'); /* filename starts at tab */
513  if (s==NULL) continue; /* there can be blank lines */
514  s++;
515  Perms = SetDiskPerm(Inode,Perms,Destination,s);
516  }
517  pclose(Fin);
518 
519  /* all done! */
520  /* if done right, Perms should be null. But just in case... */
521  FreeDiskPerms(Perms);
522  return(0);
523 } /* ExtractDisk() */
int Quiet
Run in quiet mode?
struct utimbuf Times
Definition: ununpack-disk.c:34
void FreeDiskPerms(permlist *List)
Deallocate perms.
Definition: ununpack-disk.c:73
void FatDiskName(char *Name)
Special handling for FAT names.
Definition: ununpack-disk.c:48
int ExtractDisk(char *Source, char *FStype, char *Destination)
Given a disk image, type of system, and a directory, extract all files!
int Verbose
Verbose level.
Definition: util.c:28
char * Pfile
Pfile name (SHA1.MD5.Size)
int s
The socket that the CLI will use to communicate.
Definition: fo_cli.c:48
int SameInode(char *Inode1, char *Inode2)
Determine if two inodes are the same.
int MkDir(char *Fname)
Smart mkdir.
Definition: utils.c:314
Structure to hold permission about an inode.
Definition: ununpack-disk.c:31
permlist * ExtractDiskPerms(char *FStype, char *Source)
Given a disk, load in all of the file permissions. Assumes Source is already quote-tainted! ...
Definition: ununpack-disk.c:92
permlist * SetDiskPerm(char *inode, permlist *List, char *Destination, char *Target)
Find a disk permission by inode, set the permissions on the file, and free the memory.
Stores all extern variables used by the agent.
struct permlist * Next
Definition: ununpack-disk.c:36
char * TaintString(char *S)
Create a string with taint quoting.
Definition: finder.c:46
int ReadLine(FILE *Fin, char *Line, int MaxLine)
Definition: repcopyin.c:77
void SafeExit(int rc)
Close scheduler and database connections, then exit.
Definition: utils.c:88
int ForceContinue
Force continue when unpack tool fails?