export negative byte values to chillispot attributes as 0, RT#5815
[freeside.git] / bin / svc_acct.import
1 #!/usr/bin/perl -Tw
2
3 use strict;
4 use vars qw(%part_svc);
5 use Date::Parse;
6 use Term::Query qw(query);
7 use Net::SCP qw(iscp);
8 use FS::UID qw(adminsuidsetup datasrc);
9 use FS::Record qw(qsearch);
10 use FS::svc_acct;
11 use FS::part_svc;
12
13 my $user = shift or die &usage;
14 adminsuidsetup $user;
15
16 push @FS::svc_acct::shells, qw(/bin/sync /sbin/shuddown /bin/halt); #others?
17
18 my($spooldir)="/usr/local/etc/freeside/export.". datasrc;
19
20 $FS::svc_acct::nossh_hack = 1;
21
22 ###
23
24 %part_svc=map { $_->svcpart, $_ } qsearch('part_svc',{'svcdb'=>'svc_acct'});
25
26 die "No services with svcdb svc_acct!\n" unless %part_svc;
27
28 print "\n\n", &menu_svc, "\n", <<END;
29 Most accounts probably have entries in passwd and users (with Port-Limit
30 nonexistant or 1).
31 END
32 my($ppp_svcpart)=&getpart;
33
34 print "\n\n", &menu_svc, "\n", <<END;
35 Some accounts have entries in passwd and users, but with Port-Limit 2 (or
36 more).
37 END
38 my($isdn_svcpart)=&getpart;
39
40 print "\n\n", &menu_svc, "\n", <<END;
41 Some accounts might have entries in users only (Port-Limit 1)
42 END
43 my($oppp_svcpart)=&getpart;
44
45 print "\n\n", &menu_svc, "\n", <<END;
46 Some accounts might have entries in users only (Port-Limit >= 2)
47 END
48 my($oisdn_svcpart)=&getpart;
49
50 print "\n\n", &menu_svc, "\n", <<END;
51 POP mail accounts have entries in passwd only, and have a particular shell.
52 END
53 my($pop_shell)=&getvalue("Enter that shell:");
54 my($popmail_svcpart)=&getpart;
55
56 print "\n\n", &menu_svc, "\n", <<END;
57 Everything else in passwd is a shell account.
58 END
59 my($shell_svcpart)=&getpart;
60
61 print "\n\n", <<END;
62 Enter the location and name of your _user_ passwd file, for example
63 "mail.isp.com:/etc/passwd" or "nis.isp.com:/etc/global/passwd"
64 END
65 my($loc_passwd)=&getvalue(":");
66 iscp("root\@$loc_passwd", "$spooldir/passwd.import");
67
68 print "\n\n", <<END;
69 Enter the location and name of your _user_ shadow file, for example
70 "mail.isp.com:/etc/shadow" or "bsd.isp.com:/etc/master.passwd"
71 END
72 my($loc_shadow)=&getvalue(":");
73 iscp("root\@$loc_shadow", "$spooldir/shadow.import");
74
75 print "\n\n", <<END;
76 Enter the location and name of your radius "users" file, for example
77 "radius.isp.com:/etc/raddb/users"
78 END
79 my($loc_users)=&getvalue(":");
80 iscp("root\@$loc_users", "$spooldir/users.import");
81
82 sub menu_svc {
83   ( join "\n", map "$_: ".$part_svc{$_}->svc, sort keys %part_svc ). "\n";
84 }
85 sub getpart {
86   $^W=0; # Term::Query isn't -w-safe
87   my $return = query "Enter part number:", 'irk', [ keys %part_svc ];
88   $^W=1;
89   $return;
90 }
91 sub getvalue {
92   my $prompt = shift;
93   $^W=0; # Term::Query isn't -w-safe
94   my $return = query $prompt, '';
95   $^W=1;
96   $return;
97 }
98
99 print "\n\n";
100
101 ###
102
103 open(PASSWD,"<$spooldir/passwd.import");
104 open(SHADOW,"<$spooldir/shadow.import");
105 open(USERS,"<$spooldir/users.import");
106
107 my(%upassword,%ip,%allparam);
108 my(%param,$username);
109 while (<USERS>) {
110   chop;
111   next if /^\s*$/;
112   next if /^\s*#/;
113   if ( /^\S/ ) {
114     /^(\w+)\s+(Auth-Type\s+=\s+Local,\s+)?Password\s+=\s+"([^"]+)"(,\s+Expiration\s+=\s+"([^"]*")\s*)?$/
115       or die "1Unexpected line in users.import: $_";
116     my($password,$expiration);
117     ($username,$password,$expiration)=(lc($1),$3,$5);
118     $password = '' if $password eq 'UNIX';
119     $upassword{$username}=$password;
120     undef %param;
121   } else {
122     die "2Unexpected line in users.import: $_";
123   }
124   while (<USERS>) {
125     chop;
126     if ( /^\s*$/ ) {
127       if ( defined $param{'radius_Framed_IP_Address'} ) {
128         $ip{$username} = $param{'radius_Framed_IP_Address'};
129         delete $param{'radius_Framed_IP_Address'};
130       } else {
131         $ip{$username} = '0e0';
132       }
133       $allparam{$username}={ %param };
134       last;
135     } elsif ( /^\s+([\w\-]+)\s=\s"?([\w\.\-\s]+)"?,?\s*$/ ) {
136       my($attribute,$value)=($1,$2);
137       $attribute =~ s/\-/_/g;
138       $param{'radius_'.$attribute}=$value;
139     } else {
140       die "3Unexpected line in users.import: $_";
141     }
142   }
143 }
144 #? incase there isn't a terminating blank line ?
145 if ( defined $param{'radius_Framed_IP_Address'} ) {
146   $ip{$username} = $param{'radius_Framed_IP_Address'};
147   delete $param{'radius_Framed_IP_Address'};
148 } else {
149   $ip{$username} = '0e0';
150 }
151 $allparam{$username}={ %param };
152
153 my(%password);
154 while (<SHADOW>) {
155   chop;
156   my($username,$password)=split(/:/);
157   #$password =~ s/^\!$/\*/;
158   #$password =~ s/\!+/\*SUSPENDED\* /;
159   $password{$username}=$password;
160 }
161
162 while (<PASSWD>) {
163   chop;
164   my($username,$x,$uid,$gid,$finger,$dir,$shell)=split(/:/);
165   my($password)=$upassword{$username} || $password{$username};
166
167   my($maxb)=${$allparam{$username}}{'radius_Port_Limit'};
168   my($svcpart);
169   if ( exists $upassword{$username} ) {
170     if ( $maxb >= 2 ) {
171       $svcpart = $isdn_svcpart
172     } elsif ( ! $maxb || $maxb == 1 ) {
173       $svcpart = $ppp_svcpart
174     } else {
175       die "Illegal Port-Limit in users ($username)!\n";
176     }
177   } elsif ( $shell eq $pop_shell ) {
178     $svcpart = $popmail_svcpart;
179   } else {
180     $svcpart = $shell_svcpart;
181   }
182
183   my($svc_acct) = new FS::svc_acct ({
184     'svcpart'   => $svcpart,
185     'username'  => $username,
186     '_password' => $password,
187     'uid'       => $uid,
188     'gid'       => $gid,
189     'finger'    => $finger,
190     'dir'       => $dir,
191     'shell'     => $shell,
192     'slipip'    => $ip{$username},
193     %{$allparam{$username}},
194   });
195   my($error);
196   $error=$svc_acct->insert;
197   die $error if $error;
198
199   delete $allparam{$username};
200   delete $upassword{$username};
201 }
202
203 #my($username);
204 foreach $username ( keys %upassword ) {
205   my($password)=$upassword{$username};
206
207   my($maxb)=${$allparam{$username}}{'radius_Port_Limit'} || 0;
208   my($svcpart);
209   if ( $maxb == 2 ) {
210     $svcpart = $oisdn_svcpart
211   } elsif ( ! $maxb || $maxb == 1 ) {
212     $svcpart = $oppp_svcpart
213   } else {
214     die "Illegal Port-Limit in users!\n";
215   }
216
217   my($svc_acct) = new FS::svc_acct ({
218     'svcpart'   => $svcpart,
219     'username'  => $username,
220     '_password' => $password,
221     'slipip'    => $ip{$username},
222     %{$allparam{$username}},
223   });
224   my($error);
225   $error=$svc_acct->insert;
226   die $error, if $error;
227
228   delete $allparam{$username};
229   delete $upassword{$username};
230 }
231
232 #
233
234 sub usage {
235   die "Usage:\n\n  svc_acct.import user\n";
236 }
237