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