c2ef4fd7f5a04177743ef2fc819530ba2fb0f90b
[freeside.git] / bin / svc_acct.import
1 #!/usr/bin/perl -Tw
2 #
3 # $Id: svc_acct.import,v 1.9 2000-06-28 12:03:53 ivan Exp $
4 #
5 # ivan@sisd.com 98-mar-9
6 #
7 # changed 'password' field to '_password' because PgSQL 6.3 reserves this word
8 #       bmccane@maxbaud.net  98-Apr-3
9 #
10 # generalized svcparts (still needs radius import) ivan@sisd.com 98-mar-23
11 #
12 # radius import, now an interactive script.  still needs erpcd import?
13 # ivan@sisd.com 98-jun-24
14 #
15 # arbitrary radius attributes ivan@sisd.com 98-aug-9
16 #
17 # don't import /var/spool/freeside/conf/shells!  ivan@sisd.com 98-aug-13
18 #
19 # $Log: svc_acct.import,v $
20 # Revision 1.9  2000-06-28 12:03:53  ivan
21 # make svc_acct more forgiving about RADIUS users files
22 #
23 # Revision 1.8  2000/02/03 05:16:52  ivan
24 # beginning of DNS and Apache support
25 #
26 # Revision 1.7  1999/07/08 02:32:26  ivan
27 # import fix, noticed by Ben Leibig and Joel Griffiths
28 #
29 # Revision 1.6  1999/07/08 01:49:00  ivan
30 # updates to avoid -w warnings from Joel Griffiths <griff@aver-computer.com>
31 #
32 # Revision 1.5  1999/03/25 08:42:19  ivan
33 # import stuff uses Term::Query and spits out (some kinds of) nonsensical input
34 #
35 # Revision 1.4  1999/03/24 00:43:38  ivan
36 # die if no relevant services
37 #
38 # Revision 1.3  1998/12/10 07:23:16  ivan
39 # use FS::Conf, need user (for datasrc)
40 #
41 # Revision 1.2  1998/10/13 12:07:51  ivan
42 # Assigns password from the shadow file for RADIUS password "UNIX"
43 #
44
45 use strict;
46 use vars qw(%part_svc);
47 use Date::Parse;
48 use Term::Query qw(query);
49 use FS::SSH qw(iscp);
50 use FS::UID qw(adminsuidsetup datasrc);
51 use FS::Record qw(qsearch);
52 use FS::svc_acct;
53 use FS::part_svc;
54
55 my $user = shift or die &usage;
56 adminsuidsetup $user;
57
58 my($spooldir)="/usr/local/etc/freeside/export.". datasrc;
59
60 $FS::svc_acct::nossh_hack = 1;
61
62 ###
63
64 %part_svc=map { $_->svcpart, $_ } qsearch('part_svc',{'svcdb'=>'svc_acct'});
65
66 die "No services with svcdb svc_acct!\n" unless %part_svc;
67
68 print "\n\n", &menu_svc, "\n", <<END;
69 Most accounts probably have entries in passwd and users (with Port-Limit
70 nonexistant or 1).
71 END
72 my($ppp_svcpart)=&getpart;
73
74 print "\n\n", &menu_svc, "\n", <<END;
75 Some accounts have entries in passwd and users, but with Port-Limit 2 (or
76 more).
77 END
78 my($isdn_svcpart)=&getpart;
79
80 print "\n\n", &menu_svc, "\n", <<END;
81 Some accounts might have entries in users only (Port-Limit 1)
82 END
83 my($oppp_svcpart)=&getpart;
84
85 print "\n\n", &menu_svc, "\n", <<END;
86 Some accounts might have entries in users only (Port-Limit >= 2)
87 END
88 my($oisdn_svcpart)=&getpart;
89
90 print "\n\n", &menu_svc, "\n", <<END;
91 POP mail accounts have entries in passwd only, and have a particular shell.
92 END
93 my($pop_shell)=&getvalue("Enter that shell:");
94 my($popmail_svcpart)=&getpart;
95
96 print "\n\n", &menu_svc, "\n", <<END;
97 Everything else in passwd is a shell account.
98 END
99 my($shell_svcpart)=&getpart;
100
101 print "\n\n", <<END;
102 Enter the location and name of your _user_ passwd file, for example
103 "mail.isp.com:/etc/passwd" or "nis.isp.com:/etc/global/passwd"
104 END
105 my($loc_passwd)=&getvalue(":");
106 iscp("root\@$loc_passwd", "$spooldir/passwd.import");
107
108 print "\n\n", <<END;
109 Enter the location and name of your _user_ shadow file, for example
110 "mail.isp.com:/etc/shadow" or "bsd.isp.com:/etc/master.passwd"
111 END
112 my($loc_shadow)=&getvalue(":");
113 iscp("root\@$loc_shadow", "$spooldir/shadow.import");
114
115 print "\n\n", <<END;
116 Enter the location and name of your radius "users" file, for example
117 "radius.isp.com:/etc/raddb/users"
118 END
119 my($loc_users)=&getvalue(":");
120 iscp("root\@$loc_users", "$spooldir/users.import");
121
122 sub menu_svc {
123   ( join "\n", map "$_: ".$part_svc{$_}->svc, sort keys %part_svc ). "\n";
124 }
125 sub getpart {
126   $^W=0; # Term::Query isn't -w-safe
127   my $return = query "Enter part number:", 'irk', [ keys %part_svc ];
128   $^W=1;
129   $return;
130 }
131 sub getvalue {
132   my $prompt = shift;
133   $^W=0; # Term::Query isn't -w-safe
134   my $return = query $prompt, '';
135   $^W=1;
136   $return;
137 }
138
139 print "\n\n";
140
141 ###
142
143 open(PASSWD,"<$spooldir/passwd.import");
144 open(SHADOW,"<$spooldir/shadow.import");
145 open(USERS,"<$spooldir/users.import");
146
147 my(%upassword,%ip,%allparam);
148 my(%param,$username);
149 while (<USERS>) {
150   chop;
151   next if /^\s*$/;
152   next if /^\s*#/;
153   if ( /^\S/ ) {
154     /^(\w+)\s+Password\s+=\s+"([^"]+)"(,\s+Expiration\s+=\s+"([^"]*")\s*)?$/
155       or die "1Unexpected line in users.import: $_";
156     my($password,$expiration);
157     ($username,$password,$expiration)=(lc($1),$2,$4);
158     $password = '' if $password eq 'UNIX';
159     $upassword{$username}=$password;
160     undef %param;
161   } else {
162     die "2Unexpected line in users.import: $_";
163   }
164   while (<USERS>) {
165     chop;
166     if ( /^\s*$/ ) {
167       if ( defined $param{'radius_Framed_IP_Address'} ) {
168         $ip{$username} = $param{'radius_Framed_IP_Address'};
169         delete $param{'radius_Framed_IP_Address'};
170       } else {
171         $ip{$username} = '0e0';
172       }
173       $allparam{$username}={ %param };
174       last;
175     } elsif ( /^\s+([\w\-]+)\s=\s"?([\w\.\-\s]+)"?,?\s*$/ ) {
176       my($attribute,$value)=($1,$2);
177       $attribute =~ s/\-/_/g;
178       $param{'radius_'.$attribute}=$value;
179     } else {
180       die "3Unexpected line in users.import: $_";
181     }
182   }
183 }
184 #? incase there isn't a terminating blank line ?
185 if ( defined $param{'radius_Framed_IP_Address'} ) {
186   $ip{$username} = $param{'radius_Framed_IP_Address'};
187   delete $param{'radius_Framed_IP_Address'};
188 } else {
189   $ip{$username} = '0e0';
190 }
191 $allparam{$username}={ %param };
192
193 my(%password);
194 while (<SHADOW>) {
195   chop;
196   my($username,$password)=split(/:/);
197   $password{$username}=$password;
198 }
199
200 while (<PASSWD>) {
201   chop;
202   my($username,$x,$uid,$gid,$finger,$dir,$shell)=split(/:/);
203   my($password)=$upassword{$username} || $password{$username};
204
205   my($maxb)=${$allparam{$username}}{'radius_Port_Limit'};
206   my($svcpart);
207   if ( exists $upassword{$username} ) {
208     if ( $maxb >= 2 ) {
209       $svcpart = $isdn_svcpart
210     } elsif ( ! $maxb || $maxb == 1 ) {
211       $svcpart = $ppp_svcpart
212     } else {
213       die "Illegal Port-Limit in users ($username)!\n";
214     }
215   } elsif ( $shell eq $pop_shell ) {
216     $svcpart = $popmail_svcpart;
217   } else {
218     $svcpart = $shell_svcpart;
219   }
220
221   my($svc_acct) = new FS::svc_acct ({
222     'svcpart'  => $svcpart,
223     'username' => $username,
224     'password' => $password,
225     'uid'      => $uid,
226     'gid'      => $gid,
227     'finger'   => $finger,
228     'dir'      => $dir,
229     'shell'    => $shell,
230     'slipip'   => $ip{$username},
231     %{$allparam{$username}},
232   });
233   my($error);
234   $error=$svc_acct->insert;
235   die $error if $error;
236
237   delete $allparam{$username};
238   delete $upassword{$username};
239 }
240
241 #my($username);
242 foreach $username ( keys %upassword ) {
243   my($password)=$upassword{$username};
244
245   my($maxb)=${$allparam{$username}}{'radius_Port_Limit'} || 0;
246   my($svcpart);
247   if ( $maxb == 2 ) {
248     $svcpart = $oisdn_svcpart
249   } elsif ( ! $maxb || $maxb == 1 ) {
250     $svcpart = $oppp_svcpart
251   } else {
252     die "Illegal Port-Limit in users!\n";
253   }
254
255   my($svc_acct) = new FS::svc_acct ({
256     'svcpart'  => $svcpart,
257     'username' => $username,
258     'password' => $password,
259     'slipip'   => $ip{$username},
260     %{$allparam{$username}},
261   });
262   my($error);
263   $error=$svc_acct->insert;
264   die $error, if $error;
265
266   delete $allparam{$username};
267   delete $upassword{$username};
268 }
269
270 #
271
272 sub usage {
273   die "Usage:\n\n  svc_acct.import user\n";
274 }
275