Example #1
0
static	void	setup_me(aClient *mp)
{
	struct	passwd	*p;

	p = getpwuid(getuid());
	strncpyzt(mp->username, (p) ? p->pw_name : "unknown",
		  sizeof(mp->username));
	(void)get_my_name(mp, mp->sockhost, sizeof(mp->sockhost)-1);
	/* I think we need no hostp, especially fake one --B.  */
	mp->hostp = NULL;
	if (mp->serv->namebuf[0] == '\0')
		strncpyzt(mp->serv->namebuf, mp->sockhost, sizeof(mp->serv->namebuf));
	if (me.info == DefInfo)
		me.info = mystrdup("IRCers United");
	mp->lasttime = mp->since = mp->firsttime = time(NULL);
	mp->hopcount = 0;
	mp->authfd = -1;
	mp->auth = mp->username;
	mp->confs = NULL;
	mp->flags = 0;
	mp->acpt = mp->from = mp;
	mp->next = NULL;
	mp->user = NULL;
	mp->fd = -1;
	SetMe(mp);
	mp->serv->snum = find_server_num (ME);
	/* we don't fill our own IP -> 0 as ip lenght */
	(void) make_user(mp,0);
	istat.is_users++;	/* here, cptr->next is NULL, see make_user() */
	mp->user->flags |= FLAGS_OPER;
	mp->serv->up = mp;
	mp->serv->maskedby = mp;
	mp->serv->version |= SV_UID;
	mp->user->server = find_server_string(mp->serv->snum);
	strncpyzt(mp->user->username, (p) ? p->pw_name : "unknown",
		  sizeof(mp->user->username));
	(void) strcpy(mp->user->host, mp->name);
	SetEOB(mp);
	istat.is_eobservers = 1;

	(void)add_to_client_hash_table(mp->name, mp);
	(void)add_to_sid_hash_table(mp->serv->sid, mp);
	strncpyzt(mp->serv->verstr, PATCHLEVEL, sizeof(mp->serv->verstr));
	setup_server_channels(mp);
}
Example #2
0
int
main(int argc, char *argv[])
{
   uid_t         uid, euid;
   int           portarg = 0,  fd;
#ifdef SAVE_MAXCLIENT_STATS
   FILE 	*mcsfp;
#endif

   memset(&me, 0, sizeof(aClient));
	
   if ((timeofday = time(NULL)) == -1) 
   {
      (void) fprintf(stderr, "ERROR: Clock Failure (%d)\n", errno);
      exit(errno);
   }
	
   build_version();
	
   Count.server = 1;		/* us */
   Count.oper = 0;
   Count.chan = 0;
   Count.local = 0;
   Count.total = 0;
   Count.invisi = 0;
   Count.unknown = 0;
   Count.max_loc = 0;
   Count.max_tot = 0;
   Count.today = 0;
   Count.weekly = 0;
   Count.monthly = 0;
   Count.yearly = 0;
   Count.start = NOW;
   Count.day = NOW;
   Count.week = NOW;
   Count.month = NOW;
   Count.year = NOW;

#ifdef SAVE_MAXCLIENT_STATS
	mcsfp=fopen(DPATH "/.maxclients", "r");
	if(mcsfp!=NULL) {
		fscanf(mcsfp, "%d %d %li %li %li %ld %ld %ld %ld", &Count.max_loc, 
			&Count.max_tot, &Count.weekly, &Count.monthly, &Count.yearly, 
			&Count.start, &Count.week, &Count.month, &Count.year);
		fclose(mcsfp);
	}
#endif
	

	
   /*
    * this code by [email protected] 
    * it is intended to keep the ircd from being swapped out. BSD
    * swapping criteria do not match the requirements of ircd
    */
	
#ifdef INITIAL_DBUFS
   dbuf_init();			/* set up some dbuf stuff to control paging */
#endif

   sbrk0 = (char *) sbrk((size_t) 0);
   uid = getuid();
   euid = geteuid();
#ifdef	PROFIL
   (void) monstartup(0, etext);
   (void) moncontrol(1);
   (void) signal(SIGUSR1, s_monitor);
#endif
	
   myargv = argv;
   (void) umask(077);		/* better safe than sorry --SRB  */
   memset((char *) &me, '\0', sizeof(me));
	
   setup_signals();
   /*
    * * All command line parameters have the syntax "-fstring"  or "-f
    * string" (e.g. the space is optional). String may  be empty. Flag
    * characters cannot be concatenated (like "-fxyz"), it would
    * conflict with the form "-fstring".
    */
   while (--argc > 0 && (*++argv)[0] == '-') 
   {
	char       *p = argv[0] + 1;
	int         flag = *p++;
		
        if (flag == '\0' || *p == '\0') 
	{
	   if (argc > 1 && argv[1][0] != '-') 
	   {
		p = *++argv;
		argc -= 1;
	   }
	   else
		p = "";
	   }
		
      switch (flag) 
      {
		 case 'a':
			bootopt |= BOOT_AUTODIE;
			break;
		 case 'c':
			bootopt |= BOOT_CONSOLE;
			break;
		 case 'q':
			bootopt |= BOOT_QUICK;
			break;
		 case 'd':
			(void) setuid((uid_t) uid);
			dpath = p;
			break;
		 case 'o':		/* Per user local daemon... */
			(void) setuid((uid_t) uid);
			bootopt |= BOOT_OPER;
			break;
#ifdef CMDLINE_CONFIG
		 case 'f':
			(void) setuid((uid_t) uid);
			configfile = p;
			break;
			
# ifdef KPATH
		 case 'k':
			(void) setuid((uid_t) uid);
			klinefile = p;
			break;
# endif
			
#endif
		 case 'h':
			strncpyzt(me.name, p, sizeof(me.name));
			break;
		 case 'i':
			bootopt |= BOOT_INETD | BOOT_AUTODIE;
			break;
		 case 'p':
			if ((portarg = atoi(p)) > 0)
			  portnum = portarg;
			break;
		 case 's':
			bootopt |= BOOT_STDERR;
			break;
		 case 't':
			(void) setuid((uid_t) uid);
			bootopt |= BOOT_TTY;
			break;
		 case 'v':
			(void) printf("ircd %s\n", version);
			exit(0);
		 case 'x':
#ifdef	DEBUGMODE
			(void) setuid((uid_t) uid);
			debuglevel = atoi(p);
			debugmode = *p ? p : "0";
			bootopt |= BOOT_DEBUG;
			break;
#else
			(void) fprintf(stderr,
				"%s: DEBUGMODE must be defined for -x y\n",
								myargv[0]);
			exit(0);
#endif
		 default:
			bad_command();
			break;
      }
   }
	
   if (chdir(dpath)) 
   {
      perror("chdir");
      exit(-1);
   }
   if ((uid != euid) && !euid) 
   {
      (void) fprintf(stderr,
	"ERROR: do not run ircd setuid root. Make it setuid a normal user.\n");
      exit(-1);
   }
	
   if (argc > 0)
	  return bad_command();	/* This should exit out  */
   initialize_ssl();

   motd = (aMotd *) NULL;
   helpfile = (aMotd *) NULL;
   motd_tm = NULL;
#ifdef SHORT_MOTD
   shortmotd = NULL;
#endif
	
   read_motd(MOTD);
   read_help(HELPFILE);
#ifdef SHORT_MOTD
   read_shortmotd(SHORTMOTD);
#endif
	
   clear_client_hash_table();
   clear_channel_hash_table();
   clear_scache_hash_table();	/* server cache name table */
   clear_ip_hash_table();	/* client host ip hash table */

   initlists();
   initclass();
   initwhowas();
   initstats();
   init_tree_parse(msgtab);
   init_send();
   NOW = time(NULL);
   open_debugfile();
   NOW = time(NULL);
   init_fdlist(&serv_fdlist);
   init_fdlist(&oper_fdlist);
   init_fdlist(&listen_fdlist);
	
#ifndef NO_PRIORITY
   init_fdlist(&busycli_fdlist);
#endif
	
   init_fdlist(&default_fdlist);
	  {
		  int i;
		  
		  for (i = MAXCONNECTIONS + 1; i > 0; i--) 
		  {
			  default_fdlist.entry[i] = i - 1;
		  }
	  }

   if ((timeofday = time(NULL)) == -1) 
   {
#ifdef USE_SYSLOG
      syslog(LOG_WARNING, "Clock Failure (%d), TS can be corrupted", errno);
#endif
      sendto_ops("Clock Failure (%d), TS can be corrupted", errno);
   }

#ifdef WINGATE_NOTICE
   strcpy(ProxyMonURL, "http://");
   strncpyzt((ProxyMonURL + 7), DEFAULT_PROXY_INFO_URL, (TOPICLEN + 1) - 7);
   strncpyzt(ProxyMonHost, MONITOR_HOST, (HOSTLEN + 1));
#endif
	
   if (portnum < 0)
	  portnum = PORTNUM;
   me.port = portnum;
   (void) init_sys();
   me.flags = FLAGS_LISTEN;
#ifndef _WIN32
   if (bootopt & BOOT_INETD) 
   {
      me.fd = 0;
      local[0] = &me;
      me.flags = FLAGS_LISTEN;
   }
   else
#endif
	  me.fd = -1;
	
#ifdef USE_SYSLOG
# define SYSLOG_ME     "ircd"
   openlog(SYSLOG_ME, LOG_PID | LOG_NDELAY, LOG_FACILITY);
#endif
   if ((fd = openconf(configfile)) == -1) 
   {
      Debug((DEBUG_FATAL, "Failed in reading configuration file %s",
				 configfile));
      (void) printf("Couldn't open configuration file %s\n",
						  configfile);
      exit(-1);
   }
   (void) initconf(bootopt, fd);
	
   /* comstuds SEPARATE_QUOTE_KLINES_BY_DATE code */
#ifdef SEPARATE_QUOTE_KLINES_BY_DATE
	  {
		  struct tm  *tmptr;
		  char        timebuffer[20], filename[200];
		  
		  tmptr = localtime(&NOW);
		  (void) strftime(timebuffer, 20, "%y%m%d", tmptr);
		  ircsprintf(filename, "%s.%s", klinefile, timebuffer);
		  if ((fd = openconf(filename)) == -1) 
		  {
			  Debug((DEBUG_ERROR, "Failed reading kline file %s",
						filename));
			  (void) printf("Couldn't open kline file %s\n",
								 filename);
		  }
		  else
			 (void) initconf(0, fd);
	  }
#else
# ifdef KPATH
   if ((fd = openconf(klinefile)) == -1) 
   {
      Debug((DEBUG_ERROR, "Failed reading kline file %s", klinefile));
      (void) printf("Couldn't open kline file %s\n", klinefile);
   }
   else
	  (void) initconf(0, fd);
# endif
#endif
   if (!(bootopt & BOOT_INETD)) 
   {
		static char star[] = "*";
		aConfItem  *aconf;
		u_long      vaddr;
		
      if ((aconf = find_me()) && portarg <= 0 && aconf->port > 0)
		  portnum = aconf->port;

      Debug((DEBUG_ERROR, "Port = %d", portnum));

      if ((aconf->passwd[0] != '\0') && (aconf->passwd[0] != '*'))
		  vaddr = inet_addr(aconf->passwd);
      else
		  vaddr = (u_long) NULL;
		
      if (inetport(&me, star, portnum, vaddr)) 
      {
			if (bootopt & BOOT_STDERR)
			  fprintf(stderr, "Couldn't bind to primary port %d\n", portnum);
#ifdef USE_SYSLOG
			(void) syslog(LOG_CRIT, "Couldn't bind to primary port %d\n", portnum);
#endif
			exit(1);
      }
   }
   else if (inetport(&me, "*", 0, 0)) 
   {
      if (bootopt & BOOT_STDERR)
		  fprintf(stderr, "Couldn't bind to port passed from inetd\n");
#ifdef USE_SYSLOG
      (void) syslog(LOG_CRIT, "Couldn't bind to port passed from inetd\n");
#endif
      exit(1);
   }
	
   (void) get_my_name(&me, me.sockhost, sizeof(me.sockhost) - 1);
   if (me.name[0] == '\0')
	  strncpyzt(me.name, me.sockhost, sizeof(me.name));
   me.hopcount = 0;
   me.authfd = -1;
   me.confs = NULL;
   me.next = NULL;
   me.user = NULL;
   me.from = &me;
   SetMe(&me);
   make_server(&me);
   me.serv->up = me.name;
   me.lasttime = me.since = me.firsttime = NOW;
   (void) add_to_client_hash_table(me.name, &me);
	
   /* We don't want to calculate these every time they are used :) */
	
   sprintf(REPORT_DO_DNS, REPORT_DO_DNS_, me.name);
   sprintf(REPORT_FIN_DNS, REPORT_FIN_DNS_, me.name);
   sprintf(REPORT_FIN_DNSC, REPORT_FIN_DNSC_, me.name);
   sprintf(REPORT_FAIL_DNS, REPORT_FAIL_DNS_, me.name);
   sprintf(REPORT_DO_ID, REPORT_DO_ID_, me.name);
   sprintf(REPORT_FIN_ID, REPORT_FIN_ID_, me.name);
   sprintf(REPORT_FAIL_ID, REPORT_FAIL_ID_, me.name);
   R_do_dns = strlen(REPORT_DO_DNS);
   R_fin_dns = strlen(REPORT_FIN_DNS);
   R_fin_dnsc = strlen(REPORT_FIN_DNSC);
   R_fail_dns = strlen(REPORT_FAIL_DNS);
   R_do_id = strlen(REPORT_DO_ID);
   R_fin_id = strlen(REPORT_FIN_ID);
   R_fail_id = strlen(REPORT_FAIL_ID);
	
   check_class();
   if (bootopt & BOOT_OPER) 
   {
      aClient    *tmp = add_connection(&me, 0);
		
      if (!tmp)
		  exit(1);
      SetMaster(tmp);
   }
   else
	  write_pidfile();
	
   Debug((DEBUG_NOTICE, "Server ready..."));
#ifdef USE_SYSLOG
   syslog(LOG_NOTICE, "Server Ready");
#endif
   NOW = time(NULL);
	
#ifndef NO_PRIORITY
   check_fdlists();
#endif
	
   if ((timeofday = time(NULL)) == -1) 
   {
#ifdef USE_SYSLOG
      syslog(LOG_WARNING, "Clock Failure (%d), TS can be corrupted", errno);
#endif
      sendto_ops("Clock Failure (%d), TS can be corrupted", errno);
   }

#ifdef DUMP_DEBUG
   dumpfp=fopen("dump.log", "w");
#endif

   io_loop();
   return 0;
}
Example #3
0
char *get_my_hostname() {
	char *hostname = NULL;
	char *port = NULL;
	char *hostport = NULL;
	char *name = get_my_name(false);
	char filename[PATH_MAX] = {0};

	// Use first Address statement in own host config file
	if(check_id(name)) {
		snprintf(filename, sizeof filename, "%s" SLASH "hosts" SLASH "%s", confbase, name);
		scan_for_hostname(filename, &hostname, &port);
		scan_for_hostname(tinc_conf, &hostname, &port);
	}

	if(hostname)
		goto done;

	// If that doesn't work, guess externally visible hostname
	fprintf(stderr, "Trying to discover externally visible hostname...\n");
	struct addrinfo *ai = str2addrinfo("tinc-vpn.org", "80", SOCK_STREAM);
	struct addrinfo *aip = ai;
	static const char request[] = "GET http://tinc-vpn.org/host.cgi HTTP/1.0\r\n\r\n";

	while(aip) {
		int s = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol);
		if(s >= 0) {
			if(connect(s, aip->ai_addr, aip->ai_addrlen)) {
				closesocket(s);
				s = -1;
			}
		}
		if(s >= 0) {
			send(s, request, sizeof request - 1, 0);
			int len = recv(s, line, sizeof line - 1, MSG_WAITALL);
			if(len > 0) {
				line[len] = 0;
				if(line[len - 1] == '\n')
					line[--len] = 0;
				char *p = strrchr(line, '\n');
				if(p && p[1])
					hostname = xstrdup(p + 1);
			}
			closesocket(s);
			if(hostname)
				break;
		}
		aip = aip->ai_next;
		continue;
	}

	if(ai)
		freeaddrinfo(ai);

	// Check that the hostname is reasonable
	if(hostname) {
		for(char *p = hostname; *p; p++) {
			if(isalnum(*p) || *p == '-' || *p == '.' || *p == ':')
				continue;
			// If not, forget it.
			free(hostname);
			hostname = NULL;
			break;
		}
	}

	if(!tty) {
		if(!hostname) {
			fprintf(stderr, "Could not determine the external address or hostname. Please set Address manually.\n");
			return NULL;
		}
		goto save;
	}

again:
	fprintf(stderr, "Please enter your host's external address or hostname");
	if(hostname)
		fprintf(stderr, " [%s]", hostname);
	fprintf(stderr, ": ");

	if(!fgets(line, sizeof line, stdin)) {
		fprintf(stderr, "Error while reading stdin: %s\n", strerror(errno));
		free(hostname);
		return NULL;
	}

	if(!rstrip(line)) {
		if(hostname)
			goto save;
		else
			goto again;
	}

	for(char *p = line; *p; p++) {
		if(isalnum(*p) || *p == '-' || *p == '.')
			continue;
		fprintf(stderr, "Invalid address or hostname.\n");
		goto again;
	}

	free(hostname);
	hostname = xstrdup(line);

save:
	if(*filename) {
		FILE *f = fopen(filename, "a");
		if(f) {
			fprintf(f, "\nAddress = %s\n", hostname);
			fclose(f);
		} else {
			fprintf(stderr, "Could not append Address to %s: %s\n", filename, strerror(errno));
		}
	}

done:
	if(port) {
		if(strchr(hostname, ':'))
			xasprintf(&hostport, "[%s]:%s", hostname, port);
		else
			xasprintf(&hostport, "%s:%s", hostname, port);
	} else {
		if(strchr(hostname, ':'))
			xasprintf(&hostport, "[%s]", hostname);
		else
			hostport = xstrdup(hostname);
	}

	free(hostname);
	free(port);
	return hostport;
}
Example #4
0
File: fsck.c Project: xentec/tinc
int fsck(const char *argv0) {
#ifdef HAVE_MINGW
	int uid = 0;
#else
	uid_t uid = getuid();
#endif

	// Check that tinc.conf is readable.

	if(access(tinc_conf, R_OK)) {
		fprintf(stderr, "ERROR: cannot read %s: %s\n", tinc_conf, strerror(errno));
		if(errno == ENOENT) {
			fprintf(stderr, "No tinc configuration found. Create a new one with:\n\n");
			print_tinc_cmd(argv0, "init");
		} else if(errno == EACCES) {
			if(uid != 0)
				fprintf(stderr, "You are currently not running tinc as root. Use sudo?\n");
			else
				fprintf(stderr, "Check the permissions of each component of the path %s.\n", tinc_conf);
		}
		return 1;
	}

	char *name = get_my_name(true);
	if(!name) {
		fprintf(stderr, "ERROR: tinc cannot run without a valid Name.\n");
		return 1;
	}

	// Check for private keys.
	// TODO: use RSAPrivateKeyFile and Ed25519PrivateKeyFile variables if present.

	struct stat st;
	char fname[PATH_MAX];
	char dname[PATH_MAX];

	ecdsa_t *ecdsa_priv = NULL;
	snprintf(fname, sizeof fname, "%s/ed25519_key.priv", confbase);

	if(stat(fname, &st)) {
		if(errno != ENOENT) {
			// Something is seriously wrong here. If we can access the directory with tinc.conf in it, we should certainly be able to stat() an existing file.
			fprintf(stderr, "ERROR: cannot read %s: %s\n", fname, strerror(errno));
			fprintf(stderr, "Please correct this error.\n");
			return 1;
		}
	} else {
		FILE *f = fopen(fname, "r");
		if(!f) {
			fprintf(stderr, "ERROR: could not open %s: %s\n", fname, strerror(errno));
			return 1;
		}
		ecdsa_priv = ecdsa_read_pem_private_key(f);
		fclose(f);
		if(!ecdsa_priv) {
			fprintf(stderr, "ERROR: No key or unusable key found in %s.\n", fname);
			fprintf(stderr, "You can generate a new Ed25519 key with:\n\n");
			print_tinc_cmd(argv0, "generate-ed25519-keys");
			return 1;
		}

		if(st.st_mode & 077) {
			fprintf(stderr, "WARNING: unsafe file permissions on %s.\n", fname);
			if(st.st_uid != uid) {
				fprintf(stderr, "You are not running %s as the same uid as %s.\n", argv0, fname);
			} else if(ask_fix()) {
				if(chmod(fname, st.st_mode & ~077))
					fprintf(stderr, "ERROR: could not change permissions of %s: %s\n", fname, strerror(errno));
				else
					fprintf(stderr, "Fixed permissions of %s.\n", fname);
			}
		}
	}

	if(!ecdsa_priv) {
		fprintf(stderr, "ERROR: No Ed25519 private key found.\n");
		fprintf(stderr, "You can generate new keys with:\n\n");
		print_tinc_cmd(argv0, "generate-keys");
		return 1;
	}

	// Check for public keys.
	// TODO: use RSAPublicKeyFile and Ed25519PublicKeyFile variables if present.

	snprintf(fname, sizeof fname, "%s/hosts/%s", confbase, name);
	if(access(fname, R_OK))
		fprintf(stderr, "WARNING: cannot read %s\n", fname);

	FILE *f;


	// TODO: this should read the Ed25519PublicKey config variable instead.
	ecdsa_t *ecdsa_pub = NULL;

	f = fopen(fname, "r");
	if(f)
		ecdsa_pub = ecdsa_read_pem_public_key(f);
	fclose(f);

	if(ecdsa_priv) {
		if(!ecdsa_pub) {
			fprintf(stderr, "WARNING: No (usable) public Ed25519 key found.\n");
			if(ask_fix()) {
				FILE *f = fopen(fname, "a");
				if(f) {
					if(ecdsa_write_pem_public_key(ecdsa_priv, f))
						fprintf(stderr, "Wrote Ed25519 public key to %s.\n", fname);
					else
						fprintf(stderr, "ERROR: could not write Ed25519 public key to %s.\n", fname);
					fclose(f);
				} else {
					fprintf(stderr, "ERROR: could not append to %s: %s\n", fname, strerror(errno));
				}
			}
		} else {
			// TODO: suggest remedies
			char *key1 = ecdsa_get_base64_public_key(ecdsa_pub);
			if(!key1) {
				fprintf(stderr, "ERROR: public Ed25519 key does not work.\n");
				return 1;
			}
			char *key2 = ecdsa_get_base64_public_key(ecdsa_priv);
			if(!key2) {
				free(key1);
				fprintf(stderr, "ERROR: private Ed25519 key does not work.\n");
				return 1;
			}
			int result = strcmp(key1, key2);
			free(key1);
			free(key2);
			if(result) {
				fprintf(stderr, "ERROR: public and private Ed25519 keys do not match.\n");
				return 1;
			}
		}
	} else {
		if(ecdsa_pub)
			fprintf(stderr, "WARNING: A public Ed25519 key was found but no private key is known.\n");
	}

	// Check whether scripts are executable

	struct dirent *ent;
	DIR *dir = opendir(confbase);
	if(!dir) {
		fprintf(stderr, "ERROR: cannot read directory %s: %s\n", confbase, strerror(errno));
		return 1;
	}

	while((ent = readdir(dir))) {
		if(strtailcmp(ent->d_name, "-up") && strtailcmp(ent->d_name, "-down"))
			continue;

		strncpy(fname, ent->d_name, sizeof fname);
		char *dash = strrchr(fname, '-');
		if(!dash)
			continue;
		*dash = 0;

		if(strcmp(fname, "tinc") && strcmp(fname, "host") && strcmp(fname, "subnet")) {
			static bool explained = false;
			fprintf(stderr, "WARNING: Unknown script %s" SLASH "%s found.\n", confbase, ent->d_name);
			if(!explained) {
				fprintf(stderr, "The only scripts in %s executed by tinc are:\n", confbase);
				fprintf(stderr, "tinc-up, tinc-down, host-up, host-down, subnet-up and subnet-down.\n");
				explained = true;
			}
			continue;
		}

		snprintf(fname, sizeof fname, "%s" SLASH "%s", confbase, ent->d_name);
		if(access(fname, R_OK | X_OK)) {
			if(errno != EACCES) {
				fprintf(stderr, "ERROR: cannot access %s: %s\n", fname, strerror(errno));
				continue;
			}
			fprintf(stderr, "WARNING: cannot read and execute %s: %s\n", fname, strerror(errno));
			if(ask_fix()) {
				if(chmod(fname, 0755))
					fprintf(stderr, "ERROR: cannot change permissions on %s: %s\n", fname, strerror(errno));
			}
		}
	}
	closedir(dir);

	snprintf(dname, sizeof dname, "%s" SLASH "hosts", confbase);
	dir = opendir(dname);
	if(!dir) {
		fprintf(stderr, "ERROR: cannot read directory %s: %s\n", dname, strerror(errno));
		return 1;
	}

	while((ent = readdir(dir))) {
		if(strtailcmp(ent->d_name, "-up") && strtailcmp(ent->d_name, "-down"))
			continue;

		strncpy(fname, ent->d_name, sizeof fname);
		char *dash = strrchr(fname, '-');
		if(!dash)
			continue;
		*dash = 0;

		snprintf(fname, sizeof fname, "%s" SLASH "hosts" SLASH "%s", confbase, ent->d_name);
		if(access(fname, R_OK | X_OK)) {
			if(errno != EACCES) {
				fprintf(stderr, "ERROR: cannot access %s: %s\n", fname, strerror(errno));
				continue;
			}
			fprintf(stderr, "WARNING: cannot read and execute %s: %s\n", fname, strerror(errno));
			if(ask_fix()) {
				if(chmod(fname, 0755))
					fprintf(stderr, "ERROR: cannot change permissions on %s: %s\n", fname, strerror(errno));
			}
		}
	}
	closedir(dir);
	
	// Check for obsolete / unsafe / unknown configuration variables.

	check_conffile(tinc_conf, true);

	dir = opendir(dname);
	if(dir) {
		while((ent = readdir(dir))) {
			if(!check_id(ent->d_name))
				continue;

			snprintf(fname, sizeof fname, "%s" SLASH "hosts" SLASH "%s", confbase, ent->d_name);
			check_conffile(fname, false);
		}
		closedir(dir);
	}

	return 0;
}
Example #5
0
int cmd_invite(int argc, char *argv[]) {
	if(argc < 2) {
		fprintf(stderr, "Not enough arguments!\n");
		return 1;
	}

	// Check validity of the new node's name
	if(!check_id(argv[1])) {
		fprintf(stderr, "Invalid name for node.\n");
		return 1;
	}

	char *myname = get_my_name(true);
	if(!myname)
		return 1;

	// Ensure no host configuration file with that name exists
	char filename[PATH_MAX];
	snprintf(filename, sizeof filename, "%s" SLASH "hosts" SLASH "%s", confbase, argv[1]);
	if(!access(filename, F_OK)) {
		fprintf(stderr, "A host config file for %s already exists!\n", argv[1]);
		return 1;
	}

	// If a daemon is running, ensure no other nodes know about this name
	bool found = false;
	if(connect_tincd(false)) {
		sendline(fd, "%d %d", CONTROL, REQ_DUMP_NODES);

		while(recvline(fd, line, sizeof line)) {
			char node[4096];
			int code, req;
			if(sscanf(line, "%d %d %s", &code, &req, node) != 3)
				break;
			if(!strcmp(node, argv[1]))
				found = true;
		}

		if(found) {
			fprintf(stderr, "A node with name %s is already known!\n", argv[1]);
			return 1;
		}
	}

	snprintf(filename, sizeof filename, "%s" SLASH "invitations", confbase);
	if(mkdir(filename, 0700) && errno != EEXIST) {
		fprintf(stderr, "Could not create directory %s: %s\n", filename, strerror(errno));
		return 1;
	}

	// Count the number of valid invitations, clean up old ones
	DIR *dir = opendir(filename);
	if(!dir) {
		fprintf(stderr, "Could not read directory %s: %s\n", filename, strerror(errno));
		return 1;
	}

	errno = 0;
	int count = 0;
	struct dirent *ent;
	time_t deadline = time(NULL) - 604800; // 1 week in the past

	while((ent = readdir(dir))) {
		if(strlen(ent->d_name) != 24)
			continue;
		char invname[PATH_MAX];
		struct stat st;
		snprintf(invname, sizeof invname, "%s" SLASH "%s", filename, ent->d_name);
		if(!stat(invname, &st)) {
			if(deadline < st.st_mtime)
				count++;
			else
				unlink(invname);
		} else {
			fprintf(stderr, "Could not stat %s: %s\n", invname, strerror(errno));
			errno = 0;
		}
	}

	closedir(dir);

	if(errno) {
		fprintf(stderr, "Error while reading directory %s: %s\n", filename, strerror(errno));
		return 1;
	}
		
	ecdsa_t *key;
	snprintf(filename, sizeof filename, "%s" SLASH "invitations" SLASH "ed25519_key.priv", confbase);

	// Remove the key if there are no outstanding invitations.
	if(!count)
		unlink(filename);

	// Create a new key if necessary.
	FILE *f = fopen(filename, "r");
	if(!f) {
		if(errno != ENOENT) {
			fprintf(stderr, "Could not read %s: %s\n", filename, strerror(errno));
			return 1;
		}

		key = ecdsa_generate();
		if(!key)
			return 1;
		f = fopen(filename, "w");
		if(!f) {
			fprintf(stderr, "Could not write %s: %s\n", filename, strerror(errno));
			return 1;
		}
		chmod(filename, 0600);
		if(!ecdsa_write_pem_private_key(key, f)) {
			fprintf(stderr, "Could not write ECDSA private key\n");
			fclose(f);
			return 1;
		}
		fclose(f);

		if(connect_tincd(false))
			sendline(fd, "%d %d", CONTROL, REQ_RELOAD);
	} else {
		key = ecdsa_read_pem_private_key(f);
		fclose(f);
		if(!key)
			fprintf(stderr, "Could not read private key from %s\n", filename);
	}

	if(!key)
		return 1;

	// Create a hash of the key.
	char hash[64];
	char *fingerprint = ecdsa_get_base64_public_key(key);
	sha512(fingerprint, strlen(fingerprint), hash);
	b64encode_urlsafe(hash, hash, 18);

	// Create a random cookie for this invitation.
	char cookie[25];
	randomize(cookie, 18);

	// Create a filename that doesn't reveal the cookie itself
	char buf[18 + strlen(fingerprint)];
	char cookiehash[64];
	memcpy(buf, cookie, 18);
	memcpy(buf + 18, fingerprint, sizeof buf - 18);
	sha512(buf, sizeof buf, cookiehash);
	b64encode_urlsafe(cookiehash, cookiehash, 18);

	b64encode_urlsafe(cookie, cookie, 18);

	// Create a file containing the details of the invitation.
	snprintf(filename, sizeof filename, "%s" SLASH "invitations" SLASH "%s", confbase, cookiehash);
	int ifd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
	if(!ifd) {
		fprintf(stderr, "Could not create invitation file %s: %s\n", filename, strerror(errno));
		return 1;
	}
	f = fdopen(ifd, "w");
	if(!f)
		abort();

	// Get the local address
	char *address = get_my_hostname();

	// Fill in the details.
	fprintf(f, "Name = %s\n", argv[1]);
	if(netname)
		fprintf(f, "NetName = %s\n", netname);
	fprintf(f, "ConnectTo = %s\n", myname);

	// Copy Broadcast and Mode
	FILE *tc = fopen(tinc_conf, "r");
	if(tc) {
		char buf[1024];
		while(fgets(buf, sizeof buf, tc)) {
			if((!strncasecmp(buf, "Mode", 4) && strchr(" \t=", buf[4]))
					|| (!strncasecmp(buf, "Broadcast", 9) && strchr(" \t=", buf[9]))) {
				fputs(buf, f);
				// Make sure there is a newline character.
				if(!strchr(buf, '\n'))
					fputc('\n', f);
			}
		}
		fclose(tc);
	}

	fprintf(f, "#---------------------------------------------------------------#\n");
	fprintf(f, "Name = %s\n", myname);

	char filename2[PATH_MAX];
	snprintf(filename2, sizeof filename2, "%s" SLASH "hosts" SLASH "%s", confbase, myname);
	fcopy(f, filename2);
	fclose(f);

	// Create an URL from the local address, key hash and cookie
	char *url;
	xasprintf(&url, "%s/%s%s", address, hash, cookie);

	// Call the inviation-created script
	char *envp[6] = {};
	xasprintf(&envp[0], "NAME=%s", myname);
	xasprintf(&envp[1], "NETNAME=%s", netname);
	xasprintf(&envp[2], "NODE=%s", argv[1]);
	xasprintf(&envp[3], "INVITATION_FILE=%s", filename);
	xasprintf(&envp[4], "INVITATION_URL=%s", url);
	execute_script("invitation-created", envp);
	for(int i = 0; i < 6 && envp[i]; i++)
		free(envp[i]);

	puts(url);
	free(url);
	free(address);

	return 0;
}