5 # To test this program, do the following
6 #Take a radius users' file, for example with:
8 #myuser Password = "apassword"
9 # User-Service = Framed-User,
10 # Framed-Protocol = PPP,
11 # Framed-Address = 255.255.255.255,
12 # Framed-Netmask = 255.255.255.255,
14 # Framed-Routing = None,
15 # Framed-Compression = 0,
16 # Ascend-Idle-Limit = 0,
17 # Ascend-Maximum-Time = 36000
21 #cat users | ./radius2ldif
24 #dn: cn=myuser, ou=Hardware, ou=EDUCAMADRID, ou=People, o=icm.es
27 #objectclass: radiusprofile
30 #userpassword: apassword
31 #radiusServiceType: Framed-User
32 #radiusFramedProtocol: PPP
33 #radiusFramedIPAddress: 255.255.255.255
34 #radiusFramedIPNetmask: 255.255.255.255
35 #radiusFramedRouting: None
36 #radiusFramedCompression: 0
38 #dn: ou=RadiusUser, ou=Groups, o=icm.es
39 #description: RadiusUser
41 #objectclass: groupOfUniqueNames
43 #uniquemember: dn: cn=myuser, ou=Hardware, ou=EDUCAMADRID, ou=People, o=icm.es
45 # (c) 2000 Javier Fern'andez-Sanguino Pen~a <jfs@computer.org>
46 # -------------------------------------------------------------------------
47 # This program is free software; you can redistribute it and/or modify
48 # it under the terms of the GNU General Public License as published by
49 # the Free Software Foundation; either version 2 of the License, or
50 # (at your option) any later version.
52 # This program is distributed in the hope that it will be useful,
53 # but WITHOUT ANY WARRANTY; without even the implied warranty of
54 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
55 # GNU General Public License for more details.
57 # You should have received a copy of the GNU General Public License
58 # along with this program; if not, write to the Free Software
59 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
60 # -----------------------------------------------------------------------
64 # currently does not encrypt passwords (takes them from outside file)
66 # Command line options
67 # -d : debugging output
68 # -p : give only password
69 # -m : set entry to modify ldap attributes
70 # -f : read encrypted passwords from file
76 # This might or might not be necessary depending if your LDAP server
77 # when importing from ldif introduces crypted passwords in the LDAP db
78 # (not necessary for Netscape's Directory Server)
79 read_passwds ($opt_f) if $opt_f;
83 $usermatch = ".*"; # only add users matching this
84 # WARNING: in order to add *all* users set this to ".*" NOT ""
88 $basedn = ", ou=Hardware, ou=EDUCAMADRID, ou=People, $domain";
91 $groupname = "RadiusUser"; # group to add in the LDAP, if null will not add
92 $group = "\n\ndn: ou=$groupname, ou=Groups, $domain";
93 # Only useful for adding the group (not yet implemented)
94 $addgroup = $group."\ndescription: $groupname\nobjectclass: top";
95 if ( $uniquemembers ) {
96 $addgroup = $addgroup."\nobjectclass: groupOfUniqueNames";
98 $addgroup = $addgroup."\nobjectclass: groupOfNames";
100 $addgroup = $addgroup."\ncn: $groupname";
101 # The following group must be created first
102 # (ldif entry), the script will *not* create it
103 #cn=$group,ou=Groups,o=icm.es
104 #description=whatever
106 #objectclass=groupOfUniqueNames
107 # (or objectclass=groupOfNames)
109 # Required: person (for userpasswords) and radiusprofile (<draft-aboba-radius-02.txt> 5 February 1998)
110 @objectClass = ( "top", "person" , "radiusprofile" );
113 # Mapping of entries (use lower case so no check needs to be make)
114 # From freeradius: rlm_ldap.c
115 # { "radiusServiceType", "Service-Type" },
116 # { "radiusFramedProtocol", "Framed-Protocol" },
117 # { "radiusFramedIPAddress", "Framed-IP-Address" },
118 # { "radiusFramedIPNetmask", "Framed-IP-Netmask" },
119 # { "radiusFramedRoute", "Framed-Route" },
120 # { "radiusFramedRouting", "Framed-Routing" },
121 # { "radiusFilterId", "Filter-Id" },
122 # { "radiusFramedMTU", "Framed-MTU" },
123 # { "radiusFramedCompression", "Framed-Compression" },
124 # { "radiusLoginIPHost", "Login-IP-Host" },
125 # { "radiusLoginService", "Login-Service" },
126 # { "radiusLoginTCPPort", "Login-TCP-Port" },
127 # { "radiusCallbackNumber", "Callback-Number" },
128 # { "radiusCallbackId", "Callback-Id" },
129 # { "radiusFramedRoute", "Framed-Route" },
130 # { "radiusFramedIPXNetwork", "Framed-IPX-Network" },
131 # { "radiusClass", "Class" },
132 # { "radiusSessionTimeout", "Session-Timeout" },
133 # { "radiusIdleTimeout", "Idle-Timeout" },
134 # { "radiusTerminationAction", "Termination-Action" },
135 # { "radiusCalledStationId", "Called-Station-Id" },
136 # { "radiusCallingStationId", "Calling-Station-Id" },
137 # { "radiusLoginLATService", "Login-LAT-Service" },
138 # { "radiusLoginLATNode", "Login-LAT-Node" },
139 # { "radiusLoginLATGroup", "Login-LAT-Group" },
140 # { "radiusFramedAppleTalkLink", "Framed-AppleTalk-Link" },
141 # { "radiusFramedAppleTalkNetwork", "Framed-AppleTalk-Network" },
142 # { "radiusFramedAppleTalkZone", "Framed-AppleTalk-Zone" },
143 # { "radiusPortLimit", "Port-Limit" },
144 # { "radiusLoginLATPort", "Login-LAT-Port" },
145 # You can change to the mappings below like this
146 # cat radius2ldif.pl | grep ^# | \
147 # perl -ne 'if ( /\{ \"(.*?)\", \"(.*?)\" \}/ ) \
148 # { $attr=lc $2; print "\$mapping{\"$attr\"} = \"$1\";\n" ; } '
151 # Warning: sometimes password must be encrypted before sent to the LDAP
152 # Which Perl libraries are available? Only way I find is through
153 # Netscape's NDS getpwenc.
154 # However NDS does the cyphering even if sending plain passwords
155 # (do all LDAP's do this?)
156 # TODO: test with OpenLDAP
157 $mapping{'password'} = "userpassword";
158 $mapping{'service-type'} = "radiusServiceType";
159 $mapping{'framed-protocol'} = "radiusFramedProtocol";
160 $mapping{'framed-ip-address'} = "radiusFramedIPAddress";
161 $mapping{'framed-ip-netmask'} = "radiusFramedIPNetmask";
162 $mapping{'framed-route'} = "radiusFramedRoute";
163 $mapping{'framed-routing'} = "radiusFramedRouting";
164 $mapping{'filter-id'} = "radiusFilterId";
165 $mapping{'framed-mtu'} = "radiusFramedMTU";
166 $mapping{'framed-compression'} = "radiusFramedCompression";
167 $mapping{'login-ip-host'} = "radiusLoginIPHost";
168 $mapping{'login-service'} = "radiusLoginService";
169 $mapping{'login-tcp-port'} = "radiusLoginTCPPort";
170 $mapping{'callback-number'} = "radiusCallbackNumber";
171 $mapping{'callback-id'} = "radiusCallbackId";
172 $mapping{'framed-ipx-network'} = "radiusFramedIPXNetwork";
173 $mapping{'class'} = "radiusClass";
174 $mapping{'session-timeout'} = "radiusSessionTimeout";
175 $mapping{'idle-timeout'} = "radiusIdleTimeout";
176 $mapping{'termination-action'} = "radiusTerminationAction";
177 $mapping{'called-station-id'} = "radiusCalledStationId";
178 $mapping{'calling-station-id'} = "radiusCallingStationId";
179 $mapping{'login-lat-service'} = "radiusLoginLATService";
180 $mapping{'login-lat-node'} = "radiusLoginLATNode";
181 $mapping{'login-lat-group'} = "radiusLoginLATGroup";
182 $mapping{'framed-appletalk-link'} = "radiusFramedAppleTalkLink";
183 $mapping{'framed-appletalk-network'} = "radiusFramedAppleTalkNetwork";
184 $mapping{'framed-appletalk-zone'} = "radiusFramedAppleTalkZone";
185 $mapping{'port-limit'} = "radiusPortLimit";
186 $mapping{'login-lat-port'} = "radiusLoginLATPort";
188 # Must be added to rlm_ldap.c (change this to suite your needs)
189 # (really not all since they are in the /etc/raddb/dictionary.compat)
190 $mapping{'framed-address'} = "radiusFramedIPAddress";
191 $mapping{'framed-ip-route'} = "radiusFramedRoute";
192 $mapping{'framed-netmask'} = "radiusFramedIPNetmask";
193 $mapping{'user-service'} = "radiusServiceType";
194 # Since this might not change they could be placed in the DEFAULT
195 # user insted of the LDAP
196 #$mapping{'ascend-metric'} = "radiusAscendMetric";
197 #$mapping{'ascend-idle-limit'} = "radiusAscendIdleLimit";
198 # But this really ought to be there :
199 $mapping{'callback_number'} = "radiusCallbackNumber";
202 # Footer of ldif entries
206 while ($line=<STDIN>) {
208 if ( $line =~ /^[\s\t]*$/ && $startentry) {
212 # Start line is hardcoded must be uid followed by password
213 # this could be changed to use any other parameter however
214 if ( $line =~ /^(\w+)\s*\t*(?:User-)?Password=(\w+)/ ) {
217 $password = $passwords{$password} if $opt_f;
218 if ( $uid =~ /$usermatch/ ) {
220 $dn=$predn.$uid.$basedn; # Start of LDIF entry
224 $header= $header."changetype: modify\n";
226 for (my $i=0; $i < $#objectClass+1; $i++) {
227 $header = $header."objectclass: ".$objectClass[$i]."\n";
230 print $header if !$opt_m;
231 print_entry ("cn",$uid);
232 print_entry ("sn",$uid);
233 # The following might be necessary (depending on the groups)
235 #print "replace: uid\n" if $opt_m;
236 #print "uid: $uid\n";
237 #print "replace: givenname\n" if $opt_m;
238 #print "givenname: $uid\n";
239 print_entry ($mapping{'password'},$password);
242 # Do this only for entries detected
243 if ( $startentry && ! $opt_p ) {
244 #Take anything that starts with a tab or spaces
245 # and ends (sometimes) with a comma
246 if ( $line =~ /^[\t\s]+(.*?)\s+=\s+(.*?),*$/ ) {
249 print "DEBUG: Got :$parameter=$value\n" if $debug;
250 if ( defined $mapping{$parameter} && $mapping{$parameter} ne "" ) {
251 print_entry ($mapping{$parameter},$value);
252 } # of if defined mapping
254 print "DEBUG: Parameter $parameter not known\n" if $debug;
262 # The list of users in the group
268 print "\n\n$group\n";
269 print "changetype: modify\n" ;
271 foreach $user ( @userlist ) {
272 $member = "member: ";
273 $member = "uniquemember: " if $uniquemembers;
274 print "$member$user\n";
281 # Reads passwords from a file in order to get the crypted
282 # version, the file must be of the following format:
283 # password cryptedversion
285 open (PASSWD,"< $file") or die ("Could not open $file: $!\n");
287 while ($line = <PASSWD>) {
289 if ( $line =~ /^(\w+)[\t\s]+(.*?)$/ ) {
299 # Prints and ldif entry given name and value
300 # if this is a modification it will print header and footer
301 my ($name, $value) = @_;
302 print $header."replace: $name\n" if $opt_m;
303 print $name.": ".$value."\n";
304 print $footer if $opt_m;