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