1 /*
2  * (c) Copyright 1992 by Panagiotis Tsirigotis
3  * (c) Sections Copyright 1998-2001 by Rob Braun
4  * All rights reserved.  The file named COPYRIGHT specifies the terms
5  * and conditions for redistribution.
6  */
7 
8 static char RCSid[] = "$Id: itox.c,v 1.4 2007-09-20 17:13:24 bbraun Exp $" ;
9 
10 #include "config.h"
11 #define EQ( s1, s2 )				( strcmp( s1, s2 ) == 0 )
12 
13 #define NUL					'\0'
14 #define static					static
15 
16 #define FIELD_WIDTH				15
17 #define DAEMON_DIR_OPTION			"-daemon_dir"
18 #define TCPD_NAME				"tcpd"
19 
20 #include <stdlib.h>
21 #include <string.h>
22 #include "sio.h"
23 #include "str.h"
24 #if !defined(linux)
25 #include "misc.h"
26 #else
27 #include <libgen.h>
28 #endif
29 
30 str_h strp ;
31 int line_count ;
32 static void print_line( const char *name, const char *value );
33 static char *next_word( const char *description );
34 static char *make_string_cat( register unsigned count, ... );
35 static char *make_pathname( register unsigned count, ... );
36 
37 
38 /*
39  * This program works only as a filter.
40  * Options:
41  *    -daemon_dir <dir_name> : if you use tcpd, this option specifies the
42  *		directory where all the daemons are.
43  *		You must specify this option if you use tcpd
44  *
45  * Note that we don't bother to free the memory we malloc.
46  */
main(int argc,char * argv[])47 int main(int argc, char *argv[] )
48 {
49 	char *s ;
50 	int uses_tcpd ;
51 	char *daemon_dirpath = NULL ;
52 
53 	if ( argc != 1 && argc != 3 )
54 	{
55 		Sprint( 2, "Usage: %s [%s dir_path]\n",
56 				basename( argv[ 0 ] ), DAEMON_DIR_OPTION ) ;
57 		exit( 1 ) ;
58 	}
59 
60 	uses_tcpd = ( argc == 3 ) ;
61 
62 	if ( uses_tcpd )
63 	{
64 		int len ;
65 
66 		daemon_dirpath = argv[ 2 ] ;
67 		len = strlen( daemon_dirpath ) ;
68 		if ( daemon_dirpath[ len-1 ] == '/' )
69 			daemon_dirpath[ --len ] = NUL ;
70 	}
71 
72 	strp = str_parse( (char *)0, " \t", STR_NOFLAGS, (int *)0 ) ;
73 
74 	while ( (s = Srdline( 0 )) )
75 	{
76 		char *word ;
77 		char *p ;
78 		char *socket_type, *protocol ;
79 		char *service ;
80 		int is_rpc ;
81 
82 		line_count++ ;
83 
84 		if ( SIOLINELEN( 0 ) == 0 || s[ 0 ] == '#' )
85 			continue ;
86 
87 		str_setstr( strp, s ) ;
88 
89 		service = word = next_word( "service name" ) ;
90 
91 		/*
92 		 * Check if it is an RPC service
93 		 */
94 		p = strchr( word, '/' ) ;
95 		if ( p != NULL )
96 			*p = 0 ;
97 		Sprint( 1, "service %s\n{\n", word ) ;
98 		if ( (is_rpc = ( p != NULL )) )
99 		{
100 			print_line( "type", "RPC" ) ;
101 			print_line( "rpc_version", p+1 ) ;
102 		}
103 
104 		socket_type = word = next_word( "socket type" ) ;
105 		print_line( "socket_type", socket_type ) ;
106 
107 		word = next_word( "protocol" ) ;
108 		p = strchr( word, '/' ) ;
109 		protocol = ( p == NULL ) ? word : p+1 ;
110 
111 		print_line( "protocol", protocol ) ;
112 
113 		word = next_word( "wait/nowait" ) ;
114 		p = strchr(word, '.');
115 		if (p != NULL)
116 		{
117 			Sprint( 2,
118 			"The entry for service %s/%s may be wrong, because\n",
119 				service, protocol);
120 			Sprint( 2,
121 			"we can't convert .max option for wait/nowait field\n");
122 			*p = '\0';
123 			print_line( "wait", EQ( word, "wait" ) ? "yes" : "no" );
124 		}
125 		else
126 			print_line( "wait", EQ( word, "wait" ) ? "yes" : "no" );
127 
128 		word = next_word( "user[.group]" ) ;
129 		p = strchr(word, '.');
130 		if (p != NULL)
131 		{
132 			*p = '\0';
133 			print_line( "user", word ) ;
134 			word = ++p;
135 			print_line( "group", word );
136 		}
137 		else
138 			print_line( "user", word ) ;
139 
140 		word = next_word( "server" ) ;
141 		if ( EQ( word, "internal" ) )
142 		{
143 			/*
144 			 * We are in trouble if this is an RPC service
145 			 */
146 			if ( is_rpc )
147 			{
148 				Sprint( 2,
149 					"The entry for service %s will be wrong because\n", service ) ;
150 				Sprint( 2, "we can't handle internal RPC services\n" ) ;
151 			}
152 			else
153 			{
154 				print_line( "type", "INTERNAL" ) ;
155 				print_line( "id",
156 					make_string_cat( 3, service,
157 						"-", socket_type ) ) ;
158 			}
159 		}
160 		else
161 		{
162 			char *server_path = word ;	/* from inetd.conf */
163 			char *server_of_server_path = basename( server_path ) ;
164 			char *server_name = next_word( "server name" ) ;
165 			char *server ;		/* for xinetd config file */
166 
167 			if ( EQ( server_of_server_path, TCPD_NAME ) )
168 			{
169 				if ( ! uses_tcpd )
170 				{
171 					Sprint( 2, "You must use option %s if you use %s\n",
172 						DAEMON_DIR_OPTION, TCPD_NAME ) ;
173 					exit( 1 ) ;
174 				}
175 				if ( server_name[ 0 ] == '/' )
176 					server = server_name ;
177 				else
178 					server = make_pathname( 2,
179 						daemon_dirpath, server_name ) ;
180 			}
181 			else
182 				server = server_path ;
183 
184 			print_line( "server", server ) ;
185 
186 			word = str_component( strp ) ;	/* 1st arg */
187 			if ( word != NULL )
188 			{
189 				Sprint( 1, "\t%-*s = %s", FIELD_WIDTH,
190 					"server_args", word ) ;
191 				while ( (word = str_component( strp )) )
192 					Sprint( 1, " %s", word ) ;
193 				Sputchar( 1, '\n' ) ;
194 			}
195 		}
196 
197 		Sprint( 1, "}\n\n" ) ;
198 	}
199 	Sflush( 1 ) ;
200 	exit( 0 ) ;
201 }
202 
203 
print_line(const char * name,const char * value)204 static void print_line( const char *name, const char *value )
205 {
206 	Sprint( 1, "\t%-*s = %s\n", FIELD_WIDTH, name, value ) ;
207 }
208 
209 
next_word(const char * description)210 static char *next_word( const char *description )
211 {
212 	char *word = str_component( strp ) ;
213 
214 	if ( word == NULL )
215 	{
216 		Sprint( 2, "Line %d: %s missing \n", line_count, description ) ;
217 		exit( 1 ) ;
218 	}
219 	return( word ) ;
220 }
221 
make_string_cat(register unsigned count,...)222 static char *make_string_cat( register unsigned count, ... )
223 {
224    va_list ap ;
225    register unsigned i ;
226    register unsigned len = 0 ;
227    register char *s, *p ;
228    char *newstring ;
229 
230    if ( count == 0 )
231       return( NULL ) ;
232 
233    va_start( ap, count ) ;
234    if (count == 1)
235    {  /* 9 out of 10 have just 1, so this optimizes it */
236       s = va_arg( ap, char * ) ;
237       va_end( ap );
238       if ( s == NULL )
239          return strdup("");
240       else
241          return strdup(s);
242    }
243    for ( i = 0 ; i < count ; i++ )
244    {
245       s = va_arg( ap, char * ) ;
246       if ( s == NULL )
247          continue ;
248       len += strlen( s ) ;
249    }
250    va_end( ap ) ;
251 
252    newstring = (char *)malloc( len + 1 ) ;
253    if ( newstring == NULL )
254       return( NULL ) ;
255 
256    p = newstring ;
257    va_start( ap, count ) ;
258    for ( i = 0 ; i < count ; i++ )
259    {
260       s = va_arg( ap, char * ) ;
261       if ( s == NULL )
262          continue ;
263       while ( (*p++ = *s++) ) ;
264       p-- ;
265    }
266    va_end( ap ) ;
267    newstring[len] = 0;	/* if len == 0, must terminate or boom! */
268    return newstring ;
269 }
270 
make_pathname(register unsigned count,...)271 static char *make_pathname( register unsigned count, ... )
272 {
273    va_list ap ;
274    register unsigned i ;
275    register unsigned len = 0 ;
276    register char *s, *p ;
277    char *pathname ;
278 
279    if ( count == 0 )
280       return( NULL ) ;
281 
282    va_start( ap, count ) ;
283    for ( i = 0 ; i < count ; i++ )
284    {
285       s = va_arg( ap, char * ) ;
286       len += strlen( s ) ;
287    }
288    va_end( ap ) ;
289 
290    pathname = (char *)malloc( len + count ) ;
291    if ( pathname == NULL )
292       return( NULL ) ;
293 
294    p = pathname ;
295    va_start( ap, count ) ;
296    for ( i = 0 ; i < count ; i++ )
297    {
298       s = va_arg( ap, char * ) ;
299       while ( (*p++ = *s++) ) ;
300       *(p-1) = '/' ;         /* change '\0' to '/' */
301    }
302    *(p-1) = '\0' ;
303    va_end( ap ) ;
304    return( pathname ) ;
305 }
306 
307