001  #!/usr/bin/perl
002  use English;
003  use Socket;
004  sub bynum {$a <=> $b;}
005  sub childhnd {
006    $childs--;
007    wait();
008    return;
009  }
010  sub timeout {
011    exit(0);
012  }
013  sub dprint {
014    my($line)=@_;
015    unless ($SILENT)
016    {
017       print "$line";
018    }
019  }
020  if ($ARGV[0] =~ /^silent$/i) {$SILENT=1;}
021  $|=1;
022  &dprint("\n***** Random Ident Server 0.9.0b *****\n");
023  opendir(ISPELL,"/usr/lib/ispell")|| die "No /usr/lib/ispell dir found\n";
024  @files=readdir(ISPELL);
025  closedir(ISPELL);
026  $index=0;
027  while (($index <= $#files)&&(!$usefile))
028  {
029    $file=$files[$index];
030    if ($file =~ /\.hash$/)
031    {
032      $usefile=$file;
033    }
034    $index++;
035  }
036  unless ($usefile) {print "No hash file found in /usr/lib/ispell\n";exit;}
037  &dprint("* Using file /usr/lib/ispell/$usefile\n");
038  &dprint("* Counting usable words\n");
039  open(STR1,"/usr/bin/strings /usr/lib/ispell/$usefile|")||die "Cant start strings";
040  while(<STR1>)
041  {
042    chomp();
043    chomp();
044    $line=lc($_);
045    $len=length($line);
046    if (($line =~ /^[a-z]+$/)&&($len > 4) && ($len < 13))
047    {
048      $maxword++;
049      if (($maxword % 40) == 0)  { &dprint("\r  working: |  ($maxword)")};
050      if (($maxword % 40) == 10) { &dprint("\r  working: /  ($maxword)")};
051      if (($maxword % 40) == 20) { &dprint("\r  working: -  ($maxword)")};
052      if (($maxword % 40) == 30) { &dprint("\r  working: \\  ($maxword)")};
053    }
054  }
055  &dprint("\r                                               \r");
056  close(STR1);
057  $count=0;
058  $maxcount=1024+int(rand(2048));
059  &dprint("* Generating random selection of $maxcount from $maxword\n");
060  $setsize=$maxword;
061  @fetched=();
062  $fnum=0;
063  while($fnum < $maxcount)
064  {
065    $rnum=int(rand($setsize));
066    foreach $old (@fetched)
067    {
068      if ($old <= $rnum) {$rnum++;}
069    }
070    $continue=1;
071    while($continue)
072    {
073      $continue=0;
074      foreach $old (@fetched)
075      {
076         if ($old == $rnum)
077         {
078           $rnum++;
079           $continue=1;
080         }
081      }
082    }
083    $fetched[$fnum]=$rnum;
084    $fnum++;
085    $pnum=int(($fnum*$fnum*1000)/($maxcount*$maxcount))/10;
086    if (($fnum %8)==0) {&dprint("\r  working: |  ($pnum \%)");}
087    if (($fnum %8)==2) {&dprint("\r  working: /  ($pnum \%)");}
088    if (($fnum %8)==4) {&dprint("\r  working: -  ($pnum \%)");}
089    if (($fnum %8)==6) {&dprint("\r  working: \\  ($pnum \%)");}
090  }
091  &dprint("\r                                \r");
092  &dprint("* Generating insertion table\n");
093  foreach $index (0 .. $#fetched)
094  {
095    $inserttable{$fetched[$index]}=$index;
096  }
097  open(STR1,"/usr/bin/strings /usr/lib/ispell/$usefile|")||die "Cant start strings";
098  &dprint("* Aquiring names\n");
099  $count=0;
100  while(<STR1>)
101  {
102    chomp();
103    chomp();
104    $line=lc($_);
105    $len=length($line);
106    if (($line =~ /^[a-z]+$/)&&($len > 4) && ($len < 13))
107    {
108         if (defined($inserttable{$count}))
109         {
110           $words[$inserttable{$count}] =$line;
111         }
112         $count++;
113         $countp=int(1000*$count/$maxword)/10;
114         if (($count % 40) == 0)  { &dprint("\r  working: |  ($countp \%)")};
115         if (($count % 40) == 10) { &dprint("\r  working: /  ($countp \%)")};
116         if (($count % 40) == 20) { &dprint("\r  working: -  ($countp \%)")};
117         if (($count % 40) == 30) { &dprint("\r  working: \\  ($countp \%)")};
118    }
119  }
120  &dprint("\r                                 \r");
121  &dprint("* $maxcount words fetched\n");
122  &dprint("  (local ports belonging to each uniq modulus of $maxcount get\n");
123  &dprint("   a dictionary word assigned to them)\n");
124
125  if ($< != 0)
126  {
127    print "Need to be root to bind to the ident port\n";
128    exit;
129  }
130  ($pnam,$dummy,$myuid,$mygid)=getpwnam("nobody");
131  unless (($myuid) && ($mygid))
132  {
133    print "No user nobody defined\n";
134    exit;
135  }
136  if (open(PID,"/tmp/rident.pid"))
137  {
138    &dprint("* PID file found\n");
139    $opid=<PID>;
140    chomp($opid);
141    close(PID);
142    unless ($opid =~ /^\d+$/)
143    {
144      print "HEY, SOMEONE FUCKED UP MY PIDFILE /tmp/rident.pid\n";
145      exit;
146    }
147    &dprint("* Checking for process with pid $opid\n");
148    open(PS,"/bin/ps -p $opid|");
149    $killit=0;
150    while (<PS>)
151    {
152       if (/ridentd.pl/)
153       {
154         $killit=1;
155       }
156    }
157    if ($killit)
158    {
159      &dprint("* Killing old instance\n");
160      kill(9,$opid);
161      sleep(1);
162    }
163    else
164    {
165      &dprint("* pid file apears to be old\n");
166    }
167  }
168  &dprint("* Binding to port 113\n");
169  $port=113;
170  $proto=getprotobyname('tcp');
171  socket(Server,PF_INET,SOCK_STREAM,$proto)|| die "socket $!";
172  setsockopt(Server,SOL_SOCKET,SO_REUSEADDR,pack("l",1))|| die "setsockopt $!";
173  bind(Server,sockaddr_in($port,INADDR_ANY))|| die "bind: $!";
174  listen(Server,SOMAXCON)||die "listen: $!";
175  &dprint("* Forking to background\n");
176  $pid=fork();
177  unless (defined($pid)) {
178    print "ERR: Forking error\n";
179    exit;
180  }
181  if ($pid)
182  {
183    open(PID,">/tmp/rident.pid");
184    print PID "$pid\n";
185    close(PID);
186    exit;
187  }
188  &dprint("* BG Process active\n");
189  &dprint("* BG Process seting uid/gid to nobody $myuid/$mygid\n");
190  unless ($)=$mygid) {print "Unable to set group ID to $mygid\n";exit;}
191  unless ($>=$myuid) {print "Unable to set user ID to $myuid\n";exit;}
192  &dprint("* Looking if we can do socketpair lookups : ");
193  if (-r "/proc/net/tcp") {
194    &dprint("Yep: LINUX\n");
195    $LOOKUP="LINUX";
196  }
197  else {
198    &dprint("NO !!!\n");
199    $LOOKUP=0;
200  }
201  $childs=0;
202  $SIG{'CHLD'}='childhnd';
203  while($paddr = accept(Client,Server))
204  {
205     ($remoteport,$remoteip)=sockaddr_in($paddr);
206     $remoteip=unpack("L",$remoteip);
207     #Limmited forking and extra sleeping, better for the service than the system to be dossed
208     if ($childs < 10)
209     {
210     $pid=fork();
211     unless (defined($pid)) {
212       print "ERR: Forking error\n";
213       exit;
214     }
215     if ($pid==0)
216     {
217       select Client;$|=1;select(STDOUT);
218       $SIG{"ALARM"}='timeout';
219       alarm(10);
220       $firstline=<Client>;
221       if ($firstline =~ /(\d+)\s*,\s*(\d*)/)
222       {
223          $port=$1;
224          $port2=$2;
225          $found=1;
226          #If there is no portablility for the lookup just skip it
227          if ($LOOKUP eq "LINUX")
228          {
229             $found=0;
230
231             $rip=sprintf("%lX",$remoteip);
232  	   while (length($rip) < 8) {$rip = "0$rip";}
233             $rprt=sprintf("%X",$port2);
234  	   while (length($rprt) < 4) {$rprt = "0$rprt";}
235  	   $lprt=sprintf("%X",$port);
236  	   while (length($lprt) < 4) {$lprt = "0$lprt";}
237             open(TCPFIL,"/proc/net/tcp");
238             while(<TCPFIL>)
239             {
240               if (/:$lprt\s+${rip}:$rprt\s+/)
241               {
242                 $found=1;
243               }
244             }
245          }
246          if ($found)
247          {
248            $word=$words[$port % $maxcount];
249            print Client "${port},${port2}:USERID:OTHER:$word\n";
250          }
251          else
252          {
253            print Client "${port},${port2}:ERROR:NO-USER\n";
254          }
255       }
256       close(Client);
257       sleep(2);
258       exit;
259     }
260     else
261     {
262       $childs++;
263     }
264     }
265     else
266     {
267       print Client "0,0:ERROR:UNKNOWN-ERROR\n";
268       close(Client);
269     }
270  }
271  print "* BG Process had a unforseen problem (rident)\n";
