]>
Commit | Line | Data |
---|---|---|
1 | #!/usr/bin/perl | |
2 | # | |
3 | # setup-openssh.pl | |
4 | # | |
5 | # Adapts the installed gsi-openssh environment to the current machine, | |
6 | # performing actions that originally occurred during the package's | |
7 | # 'make install' phase. | |
8 | # | |
9 | # Send comments/fixes/suggestions to: | |
10 | # Chase Phillips <cphillip@ncsa.uiuc.edu> | |
11 | # | |
12 | ||
13 | printf("setup-openssh.pl: Configuring gsi-openssh package\n"); | |
14 | ||
15 | # | |
16 | # Get user's GPT_LOCATION since we may be installing this using a new(er) | |
17 | # version of GPT. | |
18 | # | |
19 | ||
20 | $gptpath = $ENV{GPT_LOCATION}; | |
21 | ||
22 | # | |
23 | # And the old standby.. | |
24 | # | |
25 | ||
26 | $gpath = $ENV{GLOBUS_LOCATION}; | |
27 | if (!defined($gpath)) | |
28 | { | |
29 | die "GLOBUS_LOCATION needs to be set before running this script" | |
30 | } | |
31 | ||
32 | # | |
33 | # modify the ld library path for when we call ssh executables | |
34 | # | |
35 | ||
36 | $oldldpath = $ENV{LD_LIBRARY_PATH}; | |
37 | $newldpath = "$gpath/lib"; | |
38 | if (length($oldldpath) > 0) | |
39 | { | |
40 | $newldpath .= ":$oldldpath"; | |
41 | } | |
42 | $ENV{LD_LIBRARY_PATH} = "$newldpath"; | |
43 | ||
44 | # | |
45 | # i'm including this because other perl scripts in the gpt setup directories | |
46 | # do so | |
47 | # | |
48 | ||
49 | if (defined($gptpath)) | |
50 | { | |
51 | @INC = (@INC, "$gptpath/lib/perl", "$gpath/lib/perl"); | |
52 | } | |
53 | else | |
54 | { | |
55 | @INC = (@INC, "$gpath/lib/perl"); | |
56 | } | |
57 | ||
58 | require Grid::GPT::Setup; | |
59 | ||
60 | my $globusdir = $gpath; | |
61 | my $myname = "setup-openssh.pl"; | |
62 | ||
63 | # | |
64 | # Set up path prefixes for use in the path translations | |
65 | # | |
66 | ||
67 | $prefix = ${globusdir}; | |
68 | $exec_prefix = "${prefix}"; | |
69 | $bindir = "${exec_prefix}/bin"; | |
70 | $sbindir = "${exec_prefix}/sbin"; | |
71 | $sysconfdir = "$prefix/etc/ssh"; | |
72 | $localsshdir = "/etc/ssh"; | |
73 | $setupdir = "$prefix/setup/gsi_openssh_setup"; | |
74 | ||
75 | my $keyfiles = { | |
76 | "dsa" => "ssh_host_dsa_key", | |
77 | "rsa" => "ssh_host_rsa_key", | |
78 | "rsa1" => "ssh_host_key", | |
79 | }; | |
80 | ||
81 | sub copyKeyFiles | |
82 | { | |
83 | my($copylist) = @_; | |
84 | my($regex, $basename); | |
85 | ||
86 | if (@$copylist) | |
87 | { | |
88 | print "Copying ssh host keys...\n"; | |
89 | ||
90 | for my $f (@$copylist) | |
91 | { | |
92 | $f =~ s:/+:/:g; | |
93 | ||
94 | if (length($f) > 0) | |
95 | { | |
96 | $keyfile = "$f"; | |
97 | $pubkeyfile = "$f.pub"; | |
98 | ||
99 | action("cp $localsshdir/$keyfile $sysconfdir/$keyfile"); | |
100 | action("cp $localsshdir/$pubkeyfile $sysconfdir/$pubkeyfile"); | |
101 | } | |
102 | } | |
103 | } | |
104 | } | |
105 | ||
106 | sub isReadable | |
107 | { | |
108 | my($file) = @_; | |
109 | ||
110 | if ( ( -e $file ) && ( -r $file ) ) | |
111 | { | |
112 | return 1; | |
113 | } | |
114 | else | |
115 | { | |
116 | return 0; | |
117 | } | |
118 | } | |
119 | ||
120 | sub isPresent | |
121 | { | |
122 | my($file) = @_; | |
123 | ||
124 | if ( -e $file ) | |
125 | { | |
126 | return 1; | |
127 | } | |
128 | else | |
129 | { | |
130 | return 0; | |
131 | } | |
132 | } | |
133 | ||
134 | sub determineKeys | |
135 | { | |
136 | my($keyhash, $keylist); | |
137 | my($count); | |
138 | ||
139 | # | |
140 | # initialize our variables | |
141 | # | |
142 | ||
143 | $count = 0; | |
144 | ||
145 | $keyhash = {}; | |
146 | $keyhash->{gen} = []; # a list of keytypes to generate | |
147 | $keyhash->{copy} = []; # a list of files to copy from the | |
148 | ||
149 | $genlist = $keyhash->{gen}; | |
150 | $copylist = $keyhash->{copy}; | |
151 | ||
152 | # | |
153 | # loop over our keytypes and determine what we need to do for each of them | |
154 | # | |
155 | ||
156 | for my $keytype (keys %$keyfiles) | |
157 | { | |
158 | $basekeyfile = $keyfiles->{$keytype}; | |
159 | ||
160 | # | |
161 | # if the key's are already present, we don't need to bother with this rigamarole | |
162 | # | |
163 | ||
164 | $gkeyfile = "$sysconfdir/$basekeyfile"; | |
165 | $gpubkeyfile = "$sysconfdir/$basekeyfile.pub"; | |
166 | ||
167 | if ( isPresent($gkeyfile) && isPresent($gpubkeyfile) ) | |
168 | { | |
169 | next; | |
170 | } | |
171 | ||
172 | # | |
173 | # if we can find a copy of the keys in /etc/ssh, we'll copy them to the user's | |
174 | # globus location | |
175 | # | |
176 | ||
177 | $mainkeyfile = "$localsshdir/$basekeyfile"; | |
178 | $mainpubkeyfile = "$localsshdir/$basekeyfile.pub"; | |
179 | ||
180 | if ( isReadable($mainkeyfile) && isReadable($mainpubkeyfile) ) | |
181 | { | |
182 | push(@$copylist, $basekeyfile); | |
183 | $count++; | |
184 | next; | |
185 | } | |
186 | ||
187 | # | |
188 | # otherwise, we need to generate the key | |
189 | # | |
190 | ||
191 | push(@$genlist, $keytype); | |
192 | $count++; | |
193 | } | |
194 | ||
195 | if ($count > 0) | |
196 | { | |
197 | if ( ! -d $sysconfdir ) | |
198 | { | |
199 | print "Could not find ${sysconfdir} directory... creating\n"; | |
200 | action("mkdir -p $sysconfdir"); | |
201 | } | |
202 | } | |
203 | ||
204 | return $keyhash; | |
205 | } | |
206 | ||
207 | sub runKeyGen | |
208 | { | |
209 | my($gen_keys) = @_; | |
210 | my $keygen = "$bindir/ssh-keygen"; | |
211 | ||
212 | if (@$gen_keys && -x $keygen) | |
213 | { | |
214 | print "Generating ssh host keys...\n"; | |
215 | ||
216 | for my $k (@$gen_keys) | |
217 | { | |
218 | $keyfile = $keyfiles->{$k}; | |
219 | ||
220 | # if $sysconfdir/$keyfile doesn't exist.. | |
221 | action("$bindir/ssh-keygen -t $k -f $sysconfdir/$keyfile -N \"\""); | |
222 | } | |
223 | } | |
224 | ||
225 | return 0; | |
226 | } | |
227 | ||
228 | sub fixpaths | |
229 | { | |
230 | my $g, $h; | |
231 | ||
232 | print "Fixing sftp-server path in sshd_config...\n"; | |
233 | ||
234 | $f = "$gpath/etc/ssh/sshd_config"; | |
235 | $g = "$f.tmp"; | |
236 | ||
237 | if ( ! -f "$f" ) | |
238 | { | |
239 | die("Cannot find $f!"); | |
240 | } | |
241 | ||
242 | # | |
243 | # Grab the current mode/uid/gid for use later | |
244 | # | |
245 | ||
246 | $mode = (stat($f))[2]; | |
247 | $uid = (stat($f))[4]; | |
248 | $gid = (stat($f))[5]; | |
249 | ||
250 | # | |
251 | # Move $f into a .tmp file for the translation step | |
252 | # | |
253 | ||
254 | $result = system("mv $f $g 2>&1"); | |
255 | if ($result or $?) | |
256 | { | |
257 | die "ERROR: Unable to execute command: $!\n"; | |
258 | } | |
259 | ||
260 | open(IN, "<$g") || die ("$0: input file $g missing!\n"); | |
261 | open(OUT, ">$f") || die ("$0: unable to open output file $f!\n"); | |
262 | ||
263 | while (<IN>) | |
264 | { | |
265 | # | |
266 | # sorry for the whacky regex, but i need to verify a whole line | |
267 | # | |
268 | ||
269 | if ( /^\s*Subsystem\s+sftp\s+\S+\s*$/ ) | |
270 | { | |
271 | $_ = "Subsystem\tsftp\t$gpath/libexec/sftp-server\n"; | |
272 | $_ =~ s:/+:/:g; | |
273 | } | |
274 | print OUT "$_"; | |
275 | } # while <IN> | |
276 | ||
277 | close(OUT); | |
278 | close(IN); | |
279 | ||
280 | # | |
281 | # Remove the old .tmp file | |
282 | # | |
283 | ||
284 | $result = system("rm $g 2>&1"); | |
285 | ||
286 | if ($result or $?) | |
287 | { | |
288 | die "ERROR: Unable to execute command: $!\n"; | |
289 | } | |
290 | ||
291 | # | |
292 | # An attempt to revert the new file back to the original file's | |
293 | # mode/uid/gid | |
294 | # | |
295 | ||
296 | chmod($mode, $f); | |
297 | chown($uid, $gid, $f); | |
298 | ||
299 | return 0; | |
300 | } | |
301 | ||
302 | sub alterFileGlobusLocation | |
303 | { | |
304 | my ($in, $out) = @_; | |
305 | ||
306 | if ( ! -e $out ) | |
307 | { | |
308 | $data = readFile($in); | |
309 | $data =~ s|\@GLOBUS_LOCATION\@|$gpath|g; | |
310 | writeFile($out, $data); | |
311 | action("chmod 755 $out"); | |
312 | } | |
313 | } | |
314 | ||
315 | sub alterFiles | |
316 | { | |
317 | alterFileGlobusLocation("$setupdir/SXXsshd.in", "$sbindir/SXXsshd"); | |
318 | } | |
319 | ||
320 | ### readFile( $filename ) | |
321 | # | |
322 | # reads and returns $filename's contents | |
323 | # | |
324 | ||
325 | sub readFile | |
326 | { | |
327 | my ($filename) = @_; | |
328 | my $data; | |
329 | ||
330 | open (IN, "$filename") || die "Can't open '$filename': $!"; | |
331 | $/ = undef; | |
332 | $data = <IN>; | |
333 | $/ = "\n"; | |
334 | close(IN); | |
335 | ||
336 | return $data; | |
337 | } | |
338 | ||
339 | ### writeFile( $filename, $fileinput ) | |
340 | # | |
341 | # create the inputs to the ssl program at $filename, appending the common name to the | |
342 | # stream in the process | |
343 | # | |
344 | ||
345 | sub writeFile | |
346 | { | |
347 | my ($filename, $fileinput) = @_; | |
348 | ||
349 | # | |
350 | # test for a valid $filename | |
351 | # | |
352 | ||
353 | if ( !defined($filename) || (length($filename) lt 1) ) | |
354 | { | |
355 | die "Filename is undefined"; | |
356 | } | |
357 | ||
358 | if ( ( -e "$filename" ) && ( ! -w "$filename" ) ) | |
359 | { | |
360 | die "Cannot write to filename '$filename'"; | |
361 | } | |
362 | ||
363 | # | |
364 | # write the output to $filename | |
365 | # | |
366 | ||
367 | open(OUT, ">$filename"); | |
368 | print OUT "$fileinput"; | |
369 | close(OUT); | |
370 | } | |
371 | ||
372 | print "---------------------------------------------------------------------\n"; | |
373 | print "Hi, I'm the setup script for the gsi_openssh package! There\n"; | |
374 | print "are some last minute details that I've got to set straight\n"; | |
375 | print "in the sshd config file, along with generating the ssh keys\n"; | |
376 | print "for this machine (if it doesn't already have them).\n"; | |
377 | print "\n"; | |
378 | print "If I find a pair of host keys in /etc/ssh, I will copy them into\n"; | |
379 | print "\$GLOBUS_LOCATION/etc/ssh. If they aren't present, I will generate\n"; | |
380 | print "them for you.\n"; | |
381 | print "\n"; | |
382 | ||
383 | $response = query_boolean("Do you wish to continue with the setup package?","y"); | |
384 | if ($response eq "n") | |
385 | { | |
386 | print "\n"; | |
387 | print "Okay.. exiting gsi_openssh setup.\n"; | |
388 | ||
389 | exit 0; | |
390 | } | |
391 | ||
392 | print "\n"; | |
393 | ||
394 | $keyhash = determineKeys(); | |
395 | runKeyGen($keyhash->{gen}); | |
396 | copyKeyFiles($keyhash->{copy}); | |
397 | fixpaths(); | |
398 | alterFiles(); | |
399 | ||
400 | my $metadata = new Grid::GPT::Setup(package_name => "gsi_openssh_setup"); | |
401 | ||
402 | $metadata->finish(); | |
403 | ||
404 | print "\n"; | |
405 | print "Additional Notes:\n"; | |
406 | print "\n"; | |
407 | print " o I see that you have your GLOBUS_LOCATION environmental variable\n"; | |
408 | print " set to:\n"; | |
409 | print "\n"; | |
410 | print " \t\"$gpath\"\n"; | |
411 | print "\n"; | |
412 | print " Remember to keep this variable set (correctly) when you want to\n"; | |
413 | print " use the executables that came with this package.\n"; | |
414 | print "\n"; | |
415 | print " o You may need to set LD_LIBRARY_PATH to point to the location in\n"; | |
416 | print " which your globus libraries reside. For example:\n"; | |
417 | print "\n"; | |
418 | print " \t\$ LD_LIBRARY_PATH=\"$gpath/lib:\$LD_LIBRARY_PATH\"; \\\n"; | |
419 | print " \t export LD_LIBRARY_PATH\n"; | |
420 | print "\n"; | |
421 | print " If you wish, you may run, e.g.:\n"; | |
422 | print "\n"; | |
423 | print " \t\$ . \$GLOBUS_LOCATION/etc/globus-user-env.sh\n"; | |
424 | print "\n"; | |
425 | print " to prepare your environment for running the gsi_openssh\n"; | |
426 | print " executables.\n"; | |
427 | print "\n"; | |
428 | print "---------------------------------------------------------------------\n"; | |
429 | print "$myname: Finished configuring package 'gsi_openssh'.\n"; | |
430 | ||
431 | # | |
432 | # Just need a minimal action() subroutine for now.. | |
433 | # | |
434 | ||
435 | sub action | |
436 | { | |
437 | my ($command) = @_; | |
438 | ||
439 | printf "$command\n"; | |
440 | ||
441 | my $result = system("LD_LIBRARY_PATH=\"$gpath/lib:\$LD_LIBRARY_PATH\"; $command 2>&1"); | |
442 | ||
443 | if (($result or $?) and $command !~ m!patch!) | |
444 | { | |
445 | die "ERROR: Unable to execute command: $!\n"; | |
446 | } | |
447 | } | |
448 | ||
449 | sub query_boolean | |
450 | { | |
451 | my ($query_text, $default) = @_; | |
452 | my $nondefault, $foo, $bar; | |
453 | ||
454 | # | |
455 | # Set $nondefault to the boolean opposite of $default. | |
456 | # | |
457 | ||
458 | if ($default eq "n") | |
459 | { | |
460 | $nondefault = "y"; | |
461 | } | |
462 | else | |
463 | { | |
464 | $nondefault = "n"; | |
465 | } | |
466 | ||
467 | print "${query_text} "; | |
468 | print "[$default] "; | |
469 | ||
470 | $foo = <STDIN>; | |
471 | ($bar) = split //, $foo; | |
472 | ||
473 | if ( grep(/\s/, $bar) ) | |
474 | { | |
475 | # this is debatable. all whitespace means 'default' | |
476 | ||
477 | $bar = $default; | |
478 | } | |
479 | elsif ($bar ne $default) | |
480 | { | |
481 | # everything else means 'nondefault'. | |
482 | ||
483 | $bar = $nondefault; | |
484 | } | |
485 | else | |
486 | { | |
487 | # extraneous step. to get here, $bar should be eq to $default anyway. | |
488 | ||
489 | $bar = $default; | |
490 | } | |
491 | ||
492 | return $bar; | |
493 | } |