1 /*
2  * The Spread Toolkit.
3  *
4  * The contents of this file are subject to the Spread Open-Source
5  * License, Version 1.0 (the ``License''); you may not use
6  * this file except in compliance with the License.  You may obtain a
7  * copy of the License at:
8  *
9  * http://www.spread.org/license/
10  *
11  * or in the file ``license.txt'' found in this distribution.
12  *
13  * Software distributed under the License is distributed on an AS IS basis,
14  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
15  * for the specific language governing rights and limitations under the
16  * License.
17  *
18  * The Creators of Spread are:
19  *  Yair Amir, Michal Miskin-Amir, Jonathan Stanton.
20  *
21  *  Copyright (C) 1993-2004 Spread Concepts LLC <spread@spreadconcepts.com>
22  *
23  *  All Rights Reserved.
24  *
25  * Major Contributor(s):
26  * ---------------
27  *    Cristina Nita-Rotaru crisn@cs.purdue.edu - group communication security.
28  *    Theo Schlossnagle    jesus@omniti.com - Perl, skiplists, autoconf.
29  *    Dan Schoenblum       dansch@cnds.jhu.edu - Java interface.
30  *    John Schultz         jschultz@cnds.jhu.edu - contribution to process group membership.
31  *
32  */
33 
34 
35 /*
36 // example for a file:
37 // 4
38 // 3 132.27.1.0 [4803]
39 //	harpo	[132.28.33.22]
40 //	hazard
41 //	hal
42 // 4 132.28.3.0 3377
43 //	bih
44 //	binoc
45 // 	bbl
46 //	bbc
47 // 2 125.32.0.0 3355
48 // 	rb
49 //	rc
50 // 2 132.27.1.0
51 //      harry
52 //	harmony
53 */
54 
55 #include "arch.h"
56 
57 #ifndef	ARCH_PC_WIN95
58 
59 #include <netdb.h>
60 #include <sys/param.h>
61 #include <sys/socket.h>
62 #include <netinet/in.h>
63 #include <unistd.h>
64 
65 #else 	/* ARCH_PC_WIN95 */
66 
67 #include <winsock.h>
68 
69 #endif	/* ARCH_PC_WIN95 */
70 
71 #include <stdio.h>
72 #include <stdlib.h>
73 #include <string.h>
74 #include <assert.h>
75 
76 #include "configuration.h"
77 
78 #define ext_conf_body
79 #include "conf_body.h"
80 #undef  ext_conf_body
81 
82 #include "alarm.h"
83 #include "memory.h"
84 #include "spread_params.h"
85 
86 static	proc		My;
87 
88 /* True means allow dangerous monitor commands like partition and flow control
89  * to be handled.
90  * False means to ignore requests for those actions. THIS IS THE SAFE SETTING
91  */
92 static  bool    EnableDangerousMonitor = FALSE;
93 
94 static  port_reuse SocketPortReuse = port_reuse_auto;
95 
96 static  char    *RuntimeDir = NULL;
97 
98 static	char	*User = NULL;
99 
100 static	char	*Group = NULL;
101 
102 static  int     Link_Protocol;
103 
Conf_init(char * file_name,char * my_name)104 int		Conf_init( char *file_name, char *my_name )
105 {
106         struct hostent  *host_ptr;
107 	char	machine_name[256];
108 	char	ip[16];
109 	int	i,j;
110         unsigned int name_len;
111         char    configfile_location[MAXPATHLEN];
112 #if 0
113         int     s;
114 	char	line[132];
115 	char	buf[132];
116 	int	full;
117 	char	optional_id[20];
118 	int	iret;
119 	char	*ret;
120 	int	p;
121 	int32	i1,i2,i3,i4;
122 #endif
123 	Num_procs = 0;
124 	/* init Config, Config_procs from file
125 	   init My from host
126 	 */
127         configfile_location[0] = '\0';
128         strcat(configfile_location, SPREAD_ETCDIR);
129         strcat(configfile_location, "/spread.conf");
130 
131 	if (NULL != (yyin = fopen(file_name,"r")) )
132                 Alarm( PRINT, "Conf_init: using file: %s\n", file_name);
133 	if (yyin == NULL)
134 		if (NULL != (yyin = fopen(configfile_location, "r")) )
135                         Alarm( PRINT, "Conf_init: using file: %s\n", configfile_location);
136 	if (yyin == NULL)
137 		Alarm( EXIT, "Conf_init: error opening config file %s\n",
138 			file_name);
139 
140 	yyparse();
141 #if 0
142 	do{
143 		ret = fgets(line,132,fp);
144 		if (ret == NULL)
145 			Alarm( EXIT, "Conf_init: no number of segments \n");
146 		full = sscanf( line, "%s", buf );
147 	}while( line[0] == '#' || full <= 0 );
148 
149 	sscanf(line,"%d",&Config.num_segments);
150 	Alarm( CONF, "Conf_init: %d segments\n", Config.num_segments );
151 	for ( s=0; s < Config.num_segments; s++ )
152 	{
153 		do{
154 			ret = fgets(line,132,fp);
155 			if (ret == NULL)
156 				Alarm( EXIT, "Conf_init: no segment data line \n");
157 			full = sscanf( line, "%s", buf );
158 		}while( line[0] == '#' || full <= 0 );
159 
160 		for(i=0; i< 3; i++)
161 		{
162 			ret = strchr(line, '.' );
163 			if ( ret == NULL)
164 				Alarm( EXIT, "Conf_init: error in bcast addr\n");
165 			*ret = ' ';
166 		}
167 		iret = sscanf(line,"%d%d%d%d%d%hd",
168 			    	&Config.segments[s].num_procs,
169 				&i1,&i2,&i3,&i4,
170 			    	&Config.segments[s].port);
171 		if( iret == 5 ) Config.segments[s].port = 4803;
172 		else if( iret < 6 )
173 			Alarm( EXIT, "Conf_init: not a valid segment line: %s\n",
174 					line);
175 
176 		Alarm( CONF, "Conf_init: segment %d: with %d procs, (%d.%d.%d.%d, %hd)\n",
177 			    s, Config.segments[s].num_procs,
178 			    i1,i2,i3,i4,
179 			    Config.segments[s].port );
180 
181 		Config.segments[s].bcast_address =
182 			( (i1 << 24 ) | (i2 << 16) | (i3 << 8) | i4 );
183 
184 		for ( p=0; p < Config.segments[s].num_procs; p++ )
185 		{
186 		    do{
187 			ret = fgets(line,132,fp);
188 			if (ret == NULL)
189 				Alarm( EXIT, "Conf_init: no proc line\n");
190 			full = sscanf( line, "%s", buf );
191 		    }while( line[0] == '#' || full <= 0 );
192 
193 		    /* %19 is MAX_PROC_NAME-1 for the null */
194 
195 		    iret = sscanf(line,"%19s%s",Config_procs[Num_procs].name,
196 					optional_id);
197 		    if( iret == 1 )
198 		    {
199 			host_ptr = gethostbyname(Config_procs[Num_procs].name);
200 
201 			if ( host_ptr == 0)
202 				Alarm( EXIT, "Conf_init: no such host %s\n",
203 					Config_procs[Num_procs].name);
204 
205         		memcpy(&Config_procs[Num_procs].id, host_ptr->h_addr_list[0],
206 			       sizeof(int32) );
207 			Config_procs[Num_procs].id =
208 				htonl( Config_procs[Num_procs].id );
209 			i1= ( Config_procs[Num_procs].id & 0xff000000 ) >> 24;
210 			i2= ( Config_procs[Num_procs].id & 0x00ff0000 ) >> 16;
211 			i3= ( Config_procs[Num_procs].id & 0x0000ff00 ) >>  8;
212 			i4= Config_procs[Num_procs].id & 0x000000ff;
213 		    }else if( iret == 2 ){
214 			for(i=0; i< 3; i++)
215 			{
216 			    ret = strchr(optional_id, '.' );
217 			    if ( ret == NULL)
218 			        Alarm( EXIT,
219 	"Conf_init: error in id or not a valid host line: %s\n",line);
220 			    *ret = ' ';
221 			}
222 			sscanf(optional_id,"%d%d%d%d",&i1,&i2,&i3,&i4);
223 			Config_procs[Num_procs].id =
224 				( (i1 << 24 ) | (i2 << 16) | (i3 << 8) | i4 );
225 		    }else Alarm( EXIT, "Conf_init: not a valid host line: %s\n",
226 					line);
227 
228  		    Config_procs[Num_procs].port = Config.segments[s].port;
229  		    Config_procs[Num_procs].seg_index = s;
230  		    Config_procs[Num_procs].index_in_seg = p;
231 		    Config.segments[s].proc_ids[p] =
232 				Config_procs[Num_procs].id;
233 
234 		    Alarm( CONF, "Conf_init: \t\t%-20s\t%d.%d.%d.%d\n",
235 				Config_procs[Num_procs].name, i1,i2,i3,i4 );
236 
237 		    Num_procs++;
238 		}
239 	}
240 #endif
241 
242         fclose(yyin);
243 
244         /* Test for localhost segemnt defined with other non-localhost segments.
245          * That is an invalid configuration
246          */
247         if ( Config.num_segments > 1 ) {
248             int found_localhost = 0;
249             int found_nonlocal = 0;
250             for ( i=0; i < Config.num_segments; i++) {
251                 if ( ((Config.segments[i].bcast_address & 0xff000000) >> 24) == 127 ) {
252                     found_localhost = 1;
253                 } else {
254                     found_nonlocal = 1;
255                 }
256             }
257             if (found_nonlocal && found_localhost) {
258                 /* Both localhost and non-localhost segments exist. This is a non-functional config.*/
259                 Alarmp( SPLOG_PRINT, PRINT, "Conf_init: Invalid configuration:\n");
260                 Conf_print( &Config );
261                 Alarmp( SPLOG_PRINT, PRINT, "\n");
262                 Alarmp( SPLOG_FATAL, CONF, "Conf_init: Localhost segments can not be used along with regular network address segments.\nMost likely you need to remove or comment out the \nSpread_Segment 127.0.0.255 {...}\n section of your configuration file.\n");
263             }
264         }
265 
266 	if( my_name == NULL ){
267 		gethostname(machine_name,sizeof(machine_name));
268 		host_ptr = gethostbyname(machine_name);
269 		if( host_ptr == 0 )
270 			Alarm( EXIT, "Conf_init: could not get my ip address (my name is %s)\n",
271 				machine_name );
272                 if (host_ptr->h_addrtype != AF_INET)
273                         Alarm(EXIT, "Conf_init: Sorry, cannot handle addr types other than IPv4\n");
274                 if (host_ptr->h_length != 4)
275                         Alarm(EXIT, "Conf_init: Bad IPv4 address length\n");
276 
277 		i = -1;	/* in case host_ptr->h_length == 0 */
278                 for (j = 0; host_ptr->h_addr_list[j] != NULL; j++) {
279                         memcpy(&My.id, host_ptr->h_addr_list[j], sizeof(struct in_addr));
280 			My.id = ntohl( My.id );
281 			i = Conf_proc_by_id( My.id, &My );
282 			if( i >= 0 ) break;
283                 }
284 		if( i < 0 ) Alarm( EXIT,
285 			"Conf_init: My proc id (%d.%d.%d.%d) is not in configuration\n", IP1(My.id),IP2(My.id),IP3(My.id),IP4(My.id) );
286 
287 	}else if( ! strcmp( my_name, "Monitor" ) ){
288 		gethostname(machine_name,sizeof(machine_name));
289 		host_ptr = gethostbyname(machine_name);
290 
291 		if( host_ptr == 0 )
292 			Alarm( EXIT, "Conf_init: no such monitor host %s\n",
293 				machine_name );
294 
295         	memcpy(&My.id, host_ptr->h_addr_list[0],
296 			sizeof(int32) );
297 		My.id = ntohl( My.id );
298 
299 		name_len = strlen( machine_name );
300 		if( name_len > sizeof(My.name) ) name_len = sizeof(My.name);
301 		memcpy(My.name, machine_name, name_len );
302 		Alarm( CONF, "Conf_init: My name: %s, id: %d\n",
303 			My.name, My.id );
304 		return( 1 );
305 	}else{
306 		name_len = strlen( my_name );
307 		if( name_len > sizeof(My.name) ) name_len = sizeof(My.name);
308 		memcpy(My.name, my_name, name_len );
309 		i = Conf_proc_by_name( My.name, &My );
310 		if( i < 0  ) Alarm( EXIT,
311 				"Conf_init: My proc %s is not in configuration \n",
312 				My.name);
313 
314 	}
315 
316 	Conf_id_to_str( My.id, ip );
317 	Alarm( CONF, "Conf_init: My name: %s, id: %s, port: %hd\n",
318 		My.name, ip, My.port );
319 
320 	return( 0 );
321 }
322 
Conf()323 configuration	Conf()
324 {
325 	return Config;
326 }
327 
Conf_my()328 proc	Conf_my()
329 {
330 	return	My;
331 }
332 
Conf_set_link_protocol(int protocol)333 void    Conf_set_link_protocol(int protocol)
334 {
335         if (protocol < 0 || protocol >= MAX_PROTOCOLS) {
336                 Alarm(PRINT, "Conf_set_link_protocol: Illegal protocol type %d\n", protocol);
337                 return;
338         }
339         Link_Protocol = protocol;
340 }
341 
Conf_get_link_protocol(void)342 int     Conf_get_link_protocol(void)
343 {
344         return(Link_Protocol);
345 }
346 
347 
Conf_proc_by_id(int32u id,proc * p)348 int	Conf_proc_by_id( int32u id, proc *p )
349 {
350 	int	i,j;
351 
352 	for ( i=0; i < Num_procs; i++ )
353 	{
354                 for ( j=0; j < Config_procs[i].num_if; j++)
355                 {
356                         if ( Config_procs[i].ifc[j].ip == id )
357                         {
358                                 *p =  Config_procs[i] ;
359                                 return( i );
360                         }
361                 }
362 	}
363 	return( -1 );
364 }
365 
Conf_proc_by_name(char * name,proc * p)366 int 	Conf_proc_by_name( char *name, proc *p )
367 {
368 	int	i;
369 
370 	for ( i=0; i < Num_procs; i++ )
371 	{
372 		if ( strcmp( Config_procs[i].name, name ) == 0 )
373 		{
374 			*p = Config_procs[i];
375 			return( i );
376 		}
377 	}
378 	return( -1 );
379 }
380 
Conf_id_in_seg(segment * seg,int32u id)381 int	Conf_id_in_seg( segment *seg, int32u id )
382 {
383 	int 	i,j;
384 
385 	for ( j=0; j < seg->num_procs; j++ )
386 	{
387                 for ( i=0; i < seg->procs[j]->num_if; i++)
388                 {
389                         if ( seg->procs[j]->ifc[i].ip == id )
390                                 return( j );
391                 }
392 	}
393 	return( -1 );
394 }
Conf_proc_ref_by_id(int32u id,proc ** p)395 static  int     Conf_proc_ref_by_id( int32u id, proc **p )
396 {
397 	int	i,j;
398 
399 	for ( i=0; i < Num_procs; i++ )
400 	{
401                 for ( j=0; j < Config_procs[i].num_if; j++)
402                 {
403                         if ( Config_procs[i].ifc[j].ip == id )
404                         {
405                                 *p = &Config_procs[i];
406                                 return( i );
407                         }
408                 }
409 	}
410 	return( -1 );
411 }
412 
Conf_append_id_to_seg(segment * seg,int32u id)413 int     Conf_append_id_to_seg( segment *seg, int32u id)
414 {
415         proc *p;
416         if (Conf_proc_ref_by_id(id, &p) != -1)
417         {
418                 seg->procs[seg->num_procs] = p;
419                 seg->num_procs++;
420                 return( 0 );
421         }
422         return( -1 );
423 }
Conf_id_in_conf(configuration * config,int32u id)424 int	Conf_id_in_conf( configuration *config, int32u id )
425 {
426 	int 	i;
427 
428 	for ( i=0; i < config->num_segments; i++ )
429                 if ( Conf_id_in_seg(&(config->segments[i]), id) >= 0 )
430                         return( i );
431 	return( -1 );
432 }
433 
Conf_num_procs(configuration * config)434 int	Conf_num_procs( configuration *config )
435 {
436 	int 	i,ret;
437 
438 	ret = 0;
439 	for ( i=0; i < config->num_segments; i++ )
440 		ret += config->segments[i].num_procs;
441 
442 	return( ret );
443 }
444 
Conf_leader(configuration * config)445 int32u	Conf_leader( configuration *config )
446 {
447         int i;
448 
449         for( i=0; i < config->num_segments; i++ )
450         {
451                 if( config->segments[i].num_procs > 0 )
452                         return( config->segments[i].procs[0]->id );
453         }
454         Alarm( EXIT, "Conf_leader: Empty configuration %c",Conf_print(config));
455 	return( -1 );
456 }
457 
Conf_last(configuration * config)458 int32u	Conf_last( configuration *config )
459 {
460         int i,j;
461 
462         for( i = config->num_segments-1; i >= 0; i-- )
463         {
464                 if( config->segments[i].num_procs > 0 )
465 		{
466 			j = config->segments[i].num_procs-1;
467                         return( config->segments[i].procs[j]->id );
468 		}
469         }
470         Alarm( EXIT, "Conf_last: Empty configuration %c",Conf_print(config));
471 	return( -1 );
472 }
473 
Conf_seg_leader(configuration * config,int16 seg_index)474 int32u	Conf_seg_leader( configuration *config, int16 seg_index )
475 {
476 	if( config->segments[seg_index].num_procs > 0 )
477 	{
478 		return( config->segments[seg_index].procs[0]->id );
479 	}
480         Alarm( EXIT, "Conf_seg_leader: Empty segment %d in Conf %c",
481 		seg_index, Conf_print(config));
482 	return( -1 );
483 }
484 
Conf_seg_last(configuration * config,int16 seg_index)485 int32u	Conf_seg_last( configuration *config, int16 seg_index )
486 {
487 	int	j;
488 
489 	if( config->segments[seg_index].num_procs > 0 )
490 	{
491 		j = config->segments[seg_index].num_procs-1;
492 		return( config->segments[seg_index].procs[j]->id );
493 	}
494         Alarm( EXIT, "Conf_seg_leader: Empty segment %d in Conf %c",
495 		seg_index, Conf_print(config));
496         return(-1);
497 }
498 
Conf_num_procs_in_seg(configuration * config,int16 seg_index)499 int	Conf_num_procs_in_seg( configuration *config, int16 seg_index )
500 {
501 	return( config->segments[seg_index].num_procs );
502 }
503 
Conf_id_to_str(int32u id,char * str)504 void	Conf_id_to_str( int32u id, char *str )
505 {
506 	int32u	i1,i2,i3,i4;
507 
508 	i1 = (id & 0xff000000) >> 24;
509 	i2 = (id & 0x00ff0000) >> 16;
510 	i3 = (id & 0x0000ff00) >> 8;
511 	i4 = (id & 0x000000ff);
512 	sprintf( str, "%u.%u.%u.%u", i1, i2, i3, i4 );
513 }
514 
Conf_print(configuration * config)515 char	Conf_print(configuration *config)
516 {
517 	int 	s,p,ret;
518 	char	ip[16];
519 	proc	pr;
520 
521 	Alarm( PRINT, "--------------------\n" );
522 	Alarm( PRINT, "Configuration at %s is:\n", My.name );
523 	Alarm( PRINT, "Num Segments %d\n",config->num_segments );
524 	for ( s=0; s < config->num_segments; s++ )
525 	{
526 		Conf_id_to_str( config->segments[s].bcast_address, ip );
527 		Alarm( PRINT, "\t%d\t%-16s  %hd\n",
528 			config->segments[s].num_procs, ip,
529 			config->segments[s].port );
530 		for( p=0; p < config->segments[s].num_procs; p++)
531 		{
532 			ret = Conf_proc_by_id( config->segments[s].procs[p]->id,
533 					&pr );
534 			Conf_id_to_str( pr.id, ip );
535 			Alarm( PRINT, "\t\t%-20s\t%-16s\n", pr.name, ip );
536 		}
537 	}
538 	Alarm( PRINT, "====================" );
539 	return( '\n' );
540 }
541 
Conf_get_dangerous_monitor_state(void)542 bool    Conf_get_dangerous_monitor_state(void)
543 {
544         return(EnableDangerousMonitor);
545 }
546 
Conf_set_dangerous_monitor_state(bool new_state)547 void    Conf_set_dangerous_monitor_state(bool new_state)
548 {
549         if (new_state == FALSE) {
550                 Alarm(PRINT, "disabling Dangerous Monitor Commands!\n");
551         } else if (new_state == TRUE) {
552                 Alarm(PRINT, "ENABLING Dangerous Monitor Commands! Make sure Spread network is secured\n");
553         } else {
554                 /* invalid setting */
555                 return;
556         }
557         EnableDangerousMonitor = new_state;
558 }
559 
Conf_get_port_reuse_type(void)560 port_reuse Conf_get_port_reuse_type(void)
561 {
562         return(SocketPortReuse);
563 }
564 
Conf_set_port_reuse_type(port_reuse state)565 void    Conf_set_port_reuse_type(port_reuse state)
566 {
567         switch (state)
568         {
569         case port_reuse_auto:
570                 Alarm(PRINT, "Setting SO_REUSEADDR to auto\n");
571                 break;
572         case port_reuse_on:
573                 Alarm(PRINT, "Setting SO_REUSEADDR to always on -- make sure Spread daemon host is secured!\n");
574                 break;
575         case port_reuse_off:
576                 Alarm(PRINT, "Setting SO_REUSEADDR to always off\n");
577                 break;
578         default:
579                 /* Inavlid type -- ignored */
580                 return;
581         }
582         SocketPortReuse = state;
583 }
584 
set_param_if_valid(char ** param,char * value,char * description,unsigned int max_value_len)585 static void set_param_if_valid(char **param, char *value, char *description, unsigned int max_value_len)
586 {
587         if (value != NULL && *value != '\0')
588         {
589                 unsigned int len = strlen(value);
590                 char *old_value = *param;
591                 char *buf;
592                 if (len > max_value_len)
593                 {
594                     Alarm(EXIT, "set_param_if_valid: value string too long\n");
595                 }
596                 buf = Mem_alloc(len + 1);
597                 if (buf == NULL)
598                 {
599                         Alarm(EXIT, "set_param_if_valid: Out of memory\n");
600                 }
601                 strncpy(buf, value, len);
602                 buf[len] = '\0';
603 
604                 *param = buf;
605                 if (old_value != NULL)
606                 {
607                     dispose(old_value);
608                 }
609                 Alarm(PRINT, "Set %s to '%s'\n", description, value);
610         }
611         else
612         {
613                 Alarm(DEBUG, "Ignored invalid %s\n", description);
614         }
615 }
616 
Conf_get_runtime_dir(void)617 char    *Conf_get_runtime_dir(void)
618 {
619         return (RuntimeDir != NULL ? RuntimeDir : SP_RUNTIME_DIR);
620 }
621 
Conf_set_runtime_dir(char * dir)622 void    Conf_set_runtime_dir(char *dir)
623 {
624         set_param_if_valid(&RuntimeDir, dir, "runtime directory", MAXPATHLEN);
625 }
626 
Conf_get_user(void)627 char    *Conf_get_user(void)
628 {
629         return (User != NULL ? User : SP_USER);
630 }
631 
Conf_set_user(char * user)632 void    Conf_set_user(char *user)
633 {
634         set_param_if_valid(&User, user, "user name", 32);
635 }
636 
Conf_get_group(void)637 char    *Conf_get_group(void)
638 {
639         return (Group != NULL ? Group : SP_GROUP);
640 }
641 
Conf_set_group(char * group)642 void    Conf_set_group(char *group)
643 {
644         set_param_if_valid(&Group, group, "group name", 32);
645 }
646