Handle hostnames with upper-case letters
[webmin.git] / inetd / inetd-solaris-10-lib.pl
1 # list_services()
2 # Returns a list of services from the services file, each being an array of
3 #  line name port protocol aliases index
4 sub list_services
5 {
6 local(@rv, $l);
7 $l = 0;
8 system("$config{'get_services_command'}") if ($config{'get_services_command'});
9 open(SERVICES, $config{services_file});
10 while(<SERVICES>) {
11         chop; s/#.*$//g;
12         if (/^(\S+)\s+([0-9]+)\/(\S+)\s*(.*)$/) {
13                 push(@rv, [ $l, $1, $2, $3, $4, scalar(@rv) ]);
14                 if ($config{'ipv6'}) {
15                         push(@rv, [ $l, $1, $2, $3.'6', $4, scalar(@rv) ]);
16                         # add udp/tcp6only options for s10
17                         if (($3 eq "tcp") | ($3 eq "udp")) {
18                                 push(@rv, [ $l, $1, $2, $3.'6only',
19                                         $4, scalar(@rv) ]);
20                                 }
21                         }
22                 }
23         $l++;
24         }
25 close(SERVICES);
26 return @rv;
27 }
28
29 # create_service(name, port, proto, aliases)
30 # Add a new service to the list
31 sub create_service
32 {
33 local $p = $_[2];
34 if ($config{'ipv6'} && $p =~ /^(\S+)6.*$/) {
35         # don't add the service if it is already there
36         foreach $s (&list_services()) {
37                 return if ($s->[1] eq $_[0] && $s->[2] == $_[1] &&
38                         $s->[3] eq $1);
39                 }
40         $p =~ s/6.*$//;
41         }
42 &open_tempfile(SERVICES, ">> $config{services_file}");
43 &print_tempfile(SERVICES, "$_[0]\t$_[1]/$p",$_[3] ? "\t$_[3]\n" : "\n");
44 &close_tempfile(SERVICES);
45 system("$config{'put_services_command'}") if ($config{'put_services_command'});
46 }
47
48
49 # modify_service(line, name, port, proto, aliases)
50 # Change an existing service
51 sub modify_service
52 {
53 local(@serv, $p);
54 $p = $_[3];
55 $p =~ s/6.*$//;
56 open(SERVICES, $config{services_file});
57 @serv = <SERVICES>;
58 close(SERVICES);
59 $serv[$_[0]] = "$_[1]\t$_[2]/$p".($_[4] ? "\t$_[4]\n" : "\n");
60 &open_tempfile(SERVICES, "> $config{services_file}");
61 &print_tempfile(SERVICES, @serv);
62 &close_tempfile(SERVICES);
63 system("$config{'put_services_command'}") if ($config{'put_services_command'});
64 }
65
66 # delete_service(line)
67 sub delete_service
68 {
69 local(@serv);
70 open(SERVICES, $config{services_file});
71 @serv = <SERVICES>;
72 close(SERVICES);
73 splice(@serv, $_[0], 1);
74 &open_tempfile(SERVICES, "> $config{services_file}");
75 &print_tempfile(SERVICES, @serv);
76 &close_tempfile(SERVICES);
77 system("$config{'put_services_command'}") if ($config{'put_services_command'});
78 }
79
80 # list_protocols()
81 # Returns a list of supported protocols on this system
82 sub list_protocols
83 {
84 local(@rv);
85 open(PROT, $config{protocols_file});
86 while(<PROT>) {
87         chop; s/#.*$//g;
88         if (!/\S/) { next; }
89         /^(\S+)\s+/;
90         push(@rv, $1);
91         if ($config{'ipv6'}) {
92                 if ($1 eq 'tcp') { push(@rv, 'tcp6', 'tcp6only'); }
93                 elsif ($1 eq 'udp') { push(@rv, 'udp6', 'udp6only'); }
94                 }
95         }
96 close(PROT);
97 return &unique(@rv);
98 }
99
100 # list_inets()
101 # Returns a list of service details handled by inetd. RPC services
102 # will have a name like foo/1 or bar/1-3, where the thing after the / is
103 # the version or versions supported. For each service, the list contains
104 #  line active? rpc? name type protocol wait user path|internal args file
105 sub list_inets
106 {
107 local ($cmd, @inetadm_output, $l, $fmri, $state, @rv);
108 # for smf, we need to build a list of service instances/states
109 # using inetadm, then gather relevant properties of each instance
110 $cmd = "/usr/sbin/inetadm";
111 @inetadm_output = &backquote_logged($cmd);
112 for ($l = 1; $l < scalar @inetadm_output; $l++) {
113         # retrieve fmri, state from inetadm output
114         $inetadm_output[$l] =~ /(\S+)\s+(\S+)\s+(\S+)/;
115         $fmri = $3;
116         $state = ($2 eq "online");
117         # get instance props for fmri
118         $cmd = "/usr/sbin/inetadm -l $fmri";
119         $instance_props = &backquote_logged($cmd);
120         $instance_props=~/(isrpc=)(\w+)/;
121         $isrpc = ($2 eq "TRUE");
122         if ($isrpc) {
123                 # for rpc svc, we need version range to
124                 # append to name
125                 $rpc = "rpc\/";
126                 $instance_props=~/(rpc_low_version=)(\w+)/;
127                 $rpc_lo = $2;
128                 $instance_props=~/(rpc_high_version=)(\w+)/;
129                 $rpc_hi = $2;
130                 if ($rpc_hi eq $rpc_lo) {
131                         $rpc_range = "\/$rpc_lo";
132                 } else {
133                         $rpc_range = "\/$rpc_lo-$rpc_hi";
134                 }
135         } else {
136                 $rpc = "";
137                 $rpc_range = "";
138         }
139         $instance_props=~/(name=\")([^\"]*)/;
140         $name = "$2$rpc_range";
141         $instance_props=~/(endpoint_type=\")([^\"]*)/;
142         $endpoint_type = $2;
143         $instance_props=~/(proto=\")([^\"]*)/;
144         $proto = "$rpc$2";
145         $instance_props=~/(wait=)(\w+)/;
146         $wait = ($2 eq "TRUE") ? "wait" : "nowait";
147         $instance_props=~/(user=\")([^\"]*)/;
148         $user = $2;
149         $instance_props=~/(exec=\")([^\"]*)/;
150         $exec = $2;
151         # split exec into path to command, and command with args
152         $exec =~/(\S+)[\s]*(.*)/;
153         $cmdpath = $1;
154         $args = $2;
155         @cmdfields = split(/\//,$cmdpath);
156         $cmd = "$cmdfields[-1] $args";
157         push(@rv, [ $l, $state , $isrpc, $name, $endpoint_type, $proto,
158             $wait, $user, $exec, $cmd, $fmri]); 
159         }
160 return @rv;
161 }
162
163 # create_inet(enabled, name, type, protocol, wait, user, program, args)
164 # Add a new service to the main inetd config file
165 sub create_inet
166 {
167 local ($proto, $name, $cmd, $retcode, $inetadm_output, $fmri);
168 # we need an ugly hack to support v6only protocols. inetconv won't
169 # accept v6only so we convert to v6, then inetadm -m proto=v6only.
170 $name = $_[1];
171 $proto = $_[3];
172 if ($_[3] =~ /.*6only/) {
173         $proto =~ s/6.*$/6/;
174         }
175 &open_tempfile(INET, ">$config{inetd_conf_file}");
176 &print_tempfile(INET, "$_[1]\t$_[2]\t$proto\t$_[4]\t$_[5]\t$_[6]". 
177            ($_[7] ? "\t$_[7]\n" : "\n"));
178 &close_tempfile(INET);
179 $name =~ s/\//_/;
180 $proto =~ s/\//_/;
181 $retcode = &execute_smf_cmd("/usr/sbin/inetconv -i $config{inetd_conf_file}");
182 if ($retcode) { return undef; }
183 # we need to determine fmri of just-created svc...
184 $inetadm_output = &backquote_logged("/usr/sbin/inetadm");
185 if ($inetadm_output =~ /(.*)(svc\:\/(.)*\/$name\/$proto:default)(.*)/) {
186         $fmri = $2;
187         if ($_[3] =~ /.*6only/) {
188                 # now change proto to correct v6only value. from inetconv
189                 # operation we know fmri will be of form "svcname/proto"
190                 $retcode =
191                     &execute_smf_cmd("/usr/sbin/inetadm -m $fmri proto=$_[3]");
192                 if ($retcode) { return undef; }
193                 }
194         if (!$_[0]) {
195                 # disable svc
196                 $retcode = &execute_smf_cmd("/usr/sbin/inetadm -d $fmri");
197                 }
198         }
199 return undef;
200 }
201
202
203 # modify_inet(line, enabled, name, type, protocol,
204 #             wait, user, program, args, fmri)
205 # Modify an existing inetd service
206 sub modify_inet
207 {
208 local ($fmri, $wait, $protocol, $isrpc, $name, $rpc_lo,
209         $rpc_hi, $rpc_mods, $cmd, $args, @cmdfields, @argfields,
210         $firstarg, $argstr, $start_method, $retcode);
211 $fmri = $_[9];
212 $name = $_[2];
213 $wait = ($_[5] eq "wait") ? "TRUE" : "FALSE";
214 $protocol = $_[4];
215 $cmd = $_[7];
216 $args = $_[8];
217 # for smf, cmd name must match first arg
218 @cmdfields = split(/\//, $cmd);
219 @argfields = split(/\s+/, $args);
220 $firstarg = shift(@argfields);
221 if ($firstarg eq $cmdfields[-1]) {
222         $argstr = join(" ", @argfields);
223         $start_method = "$cmd $argstr";
224 } else {
225         &error(&text('error_smf_cmdfield', $cmd, $cmdfields[-1]));
226         return undef;
227 }
228 if ($name =~ /(^[^\/]*)\/([1-9]*)[\-]*([1-9]*)$/) {
229         $rpc_lo = $2;
230         $rpc_hi = $3;
231         $name = $1;
232         if (!$rpc_hi) { $rpc_hi = $rpc_lo; }
233         $isrpc = 1;
234         $protocol =~ s/^(rpc\/)*//;
235         $rpc_mods = "rpc_low_version=$rpc_lo rpc_high_version=$rpc_hi";
236 } else {
237         $rpc_mods = "";
238         }
239 $retcode = &execute_smf_cmd("/usr/sbin/inetadm -m $fmri name=$name endpoint_type=$_[3] proto=$protocol wait=$wait user=$_[6] exec=$start_method $rpc_mods");
240 if ($retcode) { return undef; }
241 if ($_[1]) {
242         # may need to clear maintenance state
243         &backquote_logged("/usr/sbin/svcadm clear $fmri");
244         $retcode = &execute_smf_cmd("/usr/sbin/inetadm -e $fmri");
245 } else {
246         $retcode = &execute_smf_cmd("/usr/sbin/inetadm -d $fmri");
247         }
248 return undef;
249 }
250
251
252 # delete_inet(line, fmri)
253 # Delete an internet service
254 sub delete_inet
255 {
256 local ($fmri, @fields, $svc, $retcode, $out);
257 $fmri = $_[1];
258 # before we delete, check if this is only instance for service.
259 # if so we svccfg delete the whole service, otherwise just the
260 # instance. this is to avoid leaving unwanted detritus lying
261 # around in the smf repository...
262 @fields = split(/:/,$fmri);
263 $svc = "svc:/$fields[1]";
264 $out = &backquote_logged("/usr/sbin/inetadm | /usr/bin/grep $svc | wc -l");
265 if ($?) { return undef; }
266 if ($out =~ /\s*1\s*/) {
267         # XXX need to remove manifest too?
268         &webmin_log("running svccfg delete on $svc");
269         $fmri = $svc;
270         }
271 $retcode = &execute_smf_cmd("/usr/sbin/svccfg delete -f $fmri");
272 return undef;
273 }
274
275 sub execute_smf_cmd
276 {
277 local ($cmd, $out, $retcode);
278 $cmd = $_[0];
279 $out = &backquote_logged($cmd);
280 $retcode = $?;
281 if ($retcode) {
282         &error(&text('error_smfservice', $cmd, $retcode));
283         }
284 return $retcode;
285 }
286
287 %prot_name = ("ip", "Internet Protocol",
288               "tcp", "Transmission Control Protocol",
289               "udp", "User Datagram Protocol",
290               "tcp6", "Transmission Control Protocol IPv6",
291               "tcp6only", "Transmission Control Protocol IPv6 only, no v4",
292               "udp6", "User Datagram Protocol IPv6",
293               "udp6only", "User Datagram Protocol IPv6 only, no v4");
294