Blob Blame History Raw
/*
 * lftp - file transfer program
 *
 * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <config.h>

#include "trio.h"
#include <stdlib.h>
#include <errno.h>
#include "xstring.h"
#include "netrc.h"
#include "log.h"

static bool comment(const char *s, FILE *f)
{
   if(s[0]!='#')
      return false;
   // skip entire line
   for(;;)
   {
      int ch=getc(f);
      if(ch==EOF || ch=='\n')
	 break;
   }
   return true;
}

NetRC::Entry *NetRC::LookupHost(const char *h,const char *u)
{
   char str[256];
   char chost[256]="";
   char cuser[256]="";
   char cpass[256]="";
   char cacct[256]="";

   const char *const home=getenv("HOME");
   if(!home)
      return 0;

   const char *const netrc=xstring::cat(home,"/.netrc",NULL);
   FILE *f=fopen(netrc,"r");
   if(f==NULL)
   {
      Log::global->Format(10,"notice: cannot open %s: %s\n",netrc,strerror(errno));
      return NULL;
   }

   bool host_found=false;
   bool user_found=false;
   while(fscanf(f,"%255s",str)==1)
   {
      if(comment(str,f))
	 continue;
      if(!strcmp(str,"macdef"))
      {
	 // currently macdef is ignored
	 if(fgets(str,255,f)==0)
	    break;
	 for(;;)
	 {
	    if(fgets(str,255,f)==0)
	       break;
	    if(str[strspn(str," \t\n")]==0) // macdef ends with empty line
	       break;
	 }
	 continue;
      }
      if(!strcmp(str,"default"))
      {
	 strcpy(chost,""); // ignore the default
	 continue;
      }
      if(!strcmp(str,"machine"))
      {
	 if(host_found && user_found)
	    break;
	 if(fscanf(f,"%255s",str)!=1)
	    break;
	 strcpy(chost,str);
	 // reset data for new machine.
	 cuser[0]=0;
	 cpass[0]=0;
	 cacct[0]=0;
	 host_found=!strcasecmp(chost,h);
	 user_found=false;
	 continue;
      }
      if(!strcmp(str,"login"))
      {
	 if(fscanf(f,"%255s",str)!=1)
	    break;
	 if(strcasecmp(chost,h))
	    continue;
	 strcpy(cuser,str);
	 cpass[0]=0;
	 cacct[0]=0;
	 user_found=(!u || !strcasecmp(cuser,u));
	 continue;
      }
      if(!strcmp(str,"password"))
      {
	 if(fscanf(f,"%255s",str)!=1)
	    break;
	 if(strcasecmp(chost,h) || (u && strcasecmp(cuser,u)) || cpass[0])
	    continue;
	 strcpy(cpass,str);
	 for(char *s=cpass; *s; s++)
	 {
	    if(*s=='\\' && s[1]>='0' && s[1]<'8')
	    {
	       int ch=0;
	       int n=0;
	       if(sscanf(s+1,"%3o%n",&ch,&n)!=1)
		  continue;
	       if(ch==0)
		  continue;
	       *s=ch;
	       memmove(s+1,s+1+n,strlen(s+1+n)+1);
	    }
	 }
	 continue;
      }
      if(!strcmp(str,"account"))
      {
	 if(fscanf(f,"%255s",str)!=1)
	    break;
	 if(strcasecmp(chost,h) || (u && strcasecmp(cuser,u)) || cacct[0])
	    continue;
	 strcpy(cacct,str);
	 continue;
      }
   }
   fclose(f);
   if(host_found && user_found)
   {
      Log::global->Format(10,"found netrc entry: host=%s, user=%s, pass=%s, acct=%s\n",h,cuser,cpass,cacct);
      return new Entry(h,cuser[0]?cuser:0,cpass[0]?cpass:0,cacct[0]?cacct:0);
   }
   return 0;
}