conf.c 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202
  1. /*
  2. * conf.c -- handles:
  3. *
  4. * all of the conf handling
  5. */
  6. #include "common.h"
  7. #include "conf.h"
  8. #include "shell.h"
  9. #include "binary.h"
  10. #include "debug.h"
  11. #include "chanprog.h"
  12. #include "crypt.h"
  13. #include "main.h"
  14. #include "settings.h"
  15. #include "src/mod/irc.mod/irc.h"
  16. #include "misc.h"
  17. #include "users.h"
  18. #include "misc_file.h"
  19. #include "socket.h"
  20. #include "userrec.h"
  21. #include <errno.h>
  22. #ifdef HAVE_PATHS_H
  23. # include <paths.h>
  24. #endif /* HAVE_PATHS_H */
  25. #include <sys/types.h>
  26. #include <sys/wait.h>
  27. #include <sys/stat.h>
  28. #include <time.h>
  29. #include <sys/time.h>
  30. #include <signal.h>
  31. #ifdef CYGWIN_HACKS
  32. char cfile[DIRMAX] = "";
  33. #endif /* CYGWIN_HACKS */
  34. conf_t conf; /* global conf struct */
  35. static void
  36. tellconf()
  37. {
  38. conf_bot *bot = NULL;
  39. int i = 0;
  40. sdprintf("tempdir: %s\n", replace(tempdir, conf.homedir, "~"));
  41. sdprintf("uid: %d\n", conf.uid);
  42. sdprintf("uname: %s\n", conf.uname);
  43. sdprintf("homedir: %s\n", conf.homedir);
  44. sdprintf("username: %s\n", conf.username);
  45. sdprintf("binpath: %s\n", replace(conf.binpath, conf.homedir, "~"));
  46. sdprintf("binname: %s\n", conf.binname);
  47. sdprintf("datadir: %s\n", replace(conf.datadir, conf.homedir, "~"));
  48. sdprintf("portmin: %d\n", conf.portmin);
  49. sdprintf("portmax: %d\n", conf.portmax);
  50. sdprintf("pscloak: %d\n", conf.pscloak);
  51. sdprintf("autocron: %d\n", conf.autocron);
  52. sdprintf("autouname: %d\n", conf.autouname);
  53. sdprintf("watcher: %d\n", conf.watcher);
  54. sdprintf("bots:\n");
  55. for (bot = conf.bots; bot && bot->nick; bot = bot->next) {
  56. i++;
  57. sdprintf("%d: %s%s IP: %s HOST: %s IP6: %s HOST6: %s v6: %d HUB: %d PID: %d\n", i,
  58. bot->disabled ? "/" : "",
  59. bot->nick,
  60. bot->net.ip ? bot->net.ip : "",
  61. bot->net.host ? bot->net.host : "", bot->net.ip6 ? bot->net.ip6 : "", bot->net.host6 ? bot->net.host6 : "",
  62. bot->net.v6,
  63. bot->hub,
  64. bot->pid);
  65. }
  66. if (conf.bot && ((bot = conf.bot))) {
  67. sdprintf("me:\n");
  68. sdprintf("%s%s IP: %s HOST: %s IP6: %s HOST6: %s v6: %d HUB: %d PID: %d\n",
  69. bot->disabled ? "/" : "",
  70. bot->nick,
  71. bot->net.ip ? bot->net.ip : "",
  72. bot->net.host ? bot->net.host : "", bot->net.ip6 ? bot->net.ip6 : "", bot->net.host6 ? bot->net.host6 : "",
  73. bot->net.v6,
  74. bot->hub,
  75. bot->pid);
  76. }
  77. }
  78. void spawnbot(const char *nick)
  79. {
  80. size_t size = strlen(shell_escape(nick)) + strlen(shell_escape(binname)) + 20;
  81. char *run = (char *) my_calloc(1, size);
  82. int status = 0;
  83. simple_snprintf(run, size, "%s -B %s", shell_escape(binname), shell_escape(nick));
  84. sdprintf("Spawning '%s': %s", nick, run);
  85. status = system(run);
  86. if (status == -1 || WEXITSTATUS(status))
  87. sdprintf("Failed to spawn '%s': %s", nick, strerror(errno));
  88. free(run);
  89. }
  90. /* spawn and kill bots accordingly
  91. * bots prefixxed with '/' will be killed auto if running.
  92. * if (updating) then we were called with -U or -u */
  93. void
  94. spawnbots(bool rehashed)
  95. {
  96. conf_bot *bot = NULL;
  97. for (bot = conf.bots; bot && bot->nick; bot = bot->next) {
  98. sdprintf("checking bot: %s", bot->nick);
  99. if (bot->disabled) {
  100. /* kill it if running */
  101. if (bot->pid)
  102. kill(bot->pid, SIGKILL);
  103. else
  104. continue;
  105. /* if we're updating automatically, we were called with -u and are only supposed to kill non-localhubs
  106. -if updating and we find our nick, skip
  107. -if pid exists and not updating, bot is running and we have nothing more to do, skip.
  108. */
  109. } else if ((!strcmp(bot->nick, conf.bot->nick) && (updating == UPDATE_AUTO || rehashed)) || (bot->pid && !updating)) {
  110. sdprintf(" ... skipping. Updating: %d, pid: %d", updating, bot->pid);
  111. continue;
  112. } else {
  113. /* if we are updating with -u then we need to restart ALL bots */
  114. if (updating == UPDATE_AUTO && bot->pid) {
  115. kill(bot->pid, SIGHUP);
  116. continue;
  117. }
  118. spawnbot(bot->nick);
  119. }
  120. }
  121. }
  122. int
  123. conf_killbot(const char *botnick, conf_bot *bot, int signal)
  124. {
  125. int ret = -1;
  126. if (bot) {
  127. if (bot->pid)
  128. ret = kill(bot->pid, signal);
  129. } else {
  130. for (bot = conf.bots; bot && bot->nick; bot = bot->next) {
  131. /* kill all bots but myself if botnick==NULL, otherwise just kill botnick */
  132. if ((!botnick && egg_strcasecmp(conf.bot->nick, bot->nick)) || (botnick && !egg_strcasecmp(botnick, bot->nick))) {
  133. if (bot->pid)
  134. ret = kill(bot->pid, signal);
  135. if (botnick)
  136. break;
  137. }
  138. }
  139. }
  140. return ret;
  141. }
  142. #ifndef CYGWIN_HACKS
  143. static uid_t save_euid, save_egid;
  144. static int
  145. swap_uids()
  146. {
  147. save_euid = geteuid();
  148. save_egid = getegid();
  149. return (setegid(getgid()) || seteuid(getuid()))? -1 : 0;
  150. }
  151. static int
  152. swap_uids_back()
  153. {
  154. return (setegid(save_egid) || seteuid(save_euid)) ? -1 : 0;
  155. }
  156. static int
  157. my_gettime(struct timespec *ts)
  158. {
  159. int rval;
  160. #if defined(HAVE_GETTIMEOFDAY) && (defined(HAVE_ST_MTIM) || defined(HAVE_ST_MTIMESPEC))
  161. struct timeval tv;
  162. rval = gettimeofday(&tv, NULL);
  163. ts->tv_sec = tv.tv_sec;
  164. ts->tv_nsec = tv.tv_usec * 1000;
  165. #else
  166. rval = (int)time(&ts->tv_sec);
  167. ts->tv_nsec = 0;
  168. #endif
  169. return (rval);
  170. }
  171. void
  172. confedit()
  173. {
  174. Tempfile tmpconf = Tempfile("conf");
  175. char *editor = NULL;
  176. mode_t um;
  177. int waiter;
  178. pid_t pid, xpid, localhub_pid = 0;
  179. struct stat st, sn;
  180. struct timespec ts1, ts2; /* time before and after edit */
  181. bool autowrote = 0;
  182. um = umask(077);
  183. autowrote = writeconf(NULL, tmpconf.f, CONF_COMMENT);
  184. fstat(tmpconf.fd, &st); /* for file modification compares */
  185. // tmpconf.my_close();
  186. umask(um);
  187. if (!can_stat(tmpconf.file))
  188. fatal("Cannot stat tempfile", 0);
  189. /* Okay, edit the file */
  190. if ((!((editor = getenv("VISUAL")) && strlen(editor)))
  191. && (!((editor = getenv("EDITOR")) && strlen(editor)))
  192. ) {
  193. editor = "vi";
  194. /*
  195. #if defined(DEBIAN)
  196. editor = "/usr/bin/editor";
  197. #elif defined(_PATH_VI)
  198. editor = _PATH_VI;
  199. #else
  200. editor = "/usr/ucb/vi";
  201. #endif
  202. */
  203. }
  204. signal(SIGINT, SIG_IGN);
  205. signal(SIGQUIT, SIG_IGN);
  206. signal(SIGCONT, SIG_DFL);
  207. swap_uids();
  208. my_gettime(&ts1);
  209. switch (pid = fork()) {
  210. case -1:
  211. fatal("Cannot fork", 0);
  212. case 0:
  213. {
  214. char *run = NULL;
  215. size_t size = tmpconf.len + strlen(editor) + 5;
  216. setgid(getgid());
  217. setuid(getuid());
  218. run = (char *) my_calloc(1, size);
  219. /* child */
  220. simple_snprintf(run, size, "%s %s", editor, tmpconf.file);
  221. execlp("/bin/sh", "/bin/sh", "-c", run, NULL);
  222. perror(editor);
  223. exit(1);
  224. /*NOTREACHED*/}
  225. default:
  226. /* parent */
  227. break;
  228. }
  229. /* parent */
  230. while (1) {
  231. xpid = waitpid(pid, &waiter, WUNTRACED);
  232. my_gettime(&ts2);
  233. if (xpid == -1) {
  234. fprintf(stderr, "waitpid() failed waiting for PID %d from \"%s\": %s\n", pid, editor, strerror(errno));
  235. } else if (xpid != pid) {
  236. fprintf(stderr, "wrong PID (%d != %d) from \"%s\"\n", xpid, pid, editor);
  237. goto fatal;
  238. } else if (WIFSTOPPED(waiter)) {
  239. /* raise(WSTOPSIG(waiter)); Not needed and breaks in job control shell */
  240. } else if (WIFEXITED(waiter) && WEXITSTATUS(waiter)) {
  241. fprintf(stderr, "\"%s\" exited with status %d\n", editor, WEXITSTATUS(waiter));
  242. goto fatal;
  243. } else if (WIFSIGNALED(waiter)) {
  244. fprintf(stderr, "\"%s\" killed; signal %d (%score dumped)\n", editor, WTERMSIG(waiter),
  245. # ifdef CYGWIN_HACKS
  246. 0
  247. # else
  248. WCOREDUMP(waiter)
  249. # endif
  250. /* CYGWIN_HACKS */
  251. ? "" : "no ");
  252. goto fatal;
  253. } else {
  254. break;
  255. }
  256. }
  257. signal(SIGINT, SIG_DFL);
  258. signal(SIGQUIT, SIG_DFL);
  259. swap_uids_back();
  260. if (fstat(tmpconf.fd, &sn))
  261. fatal("Error reading new config file", 0);
  262. if (!autowrote && st.st_size == sn.st_size &&
  263. mtim_getsec(st) == mtim_getsec(sn) &&
  264. mtim_getnsec(st) == mtim_getnsec(sn)) {
  265. /*
  266. * If mtime and size match but the user spent no measurable
  267. * time in the editor we can't tell if the file was changed.
  268. */
  269. #ifdef HAVE_TIMESPECSUB2
  270. timespecsub(&ts1, &ts2);
  271. #else
  272. timespecsub(&ts1, &ts2, &ts2);
  273. #endif
  274. if (timespecisset(&ts2)) {
  275. printf("* Config unchanged.\n");
  276. exit(0);
  277. }
  278. }
  279. if (conf.bots && conf.bots->pid)
  280. localhub_pid = conf.bots->pid;
  281. tmpconf.my_close();
  282. free_conf();
  283. readconf((const char *) tmpconf.file, 0); /* read cleartext conf tmp into &settings */
  284. expand_tilde(&conf.binpath);
  285. expand_tilde(&conf.datadir);
  286. unlink(tmpconf.file);
  287. conf_to_bin(&conf, 0, -1);
  288. if (localhub_pid)
  289. kill(localhub_pid, SIGUSR1);
  290. exit(0);
  291. fatal:
  292. unlink(tmpconf.file);
  293. exit(1);
  294. }
  295. #endif /* !CYGWIN_HACKS */
  296. void
  297. init_conf()
  298. {
  299. // conf.bots = (conf_bot *) my_calloc(1, sizeof(conf_bot));
  300. // conf.bots->nick = NULL;
  301. // conf.bots->next = NULL;
  302. conf.bots = NULL;
  303. conf.bot = NULL;
  304. conf.watcher = 0;
  305. #ifdef CYGWIN_HACKS
  306. conf.autocron = 0;
  307. #else
  308. conf.autocron = 1;
  309. #endif /* !CYGWIN_HACKS */
  310. conf.autouname = 0;
  311. #ifdef CYGWIN_HACKS
  312. if (homedir())
  313. conf.binpath = strdup(homedir());
  314. #else /* !CYGWIN_HACKS */
  315. conf.binpath = strdup(dirname(binname));
  316. #endif /* CYGWIN_HACKS */
  317. char *p = strrchr(binname, '/');
  318. p++;
  319. if (!strncmp(p, "wraith.", 7) && strchr(p, '-'))
  320. conf.binname = strdup("wraith");
  321. else
  322. conf.binname = strdup(p);
  323. conf.portmin = 0;
  324. conf.portmax = 0;
  325. conf.pscloak = 0;
  326. conf.uid = -1;
  327. conf.uname = NULL;
  328. conf.username = NULL;
  329. conf.homedir = NULL;
  330. conf.datadir = strdup("./...");
  331. expand_tilde(&conf.datadir);
  332. }
  333. /* FIXME: Remove after 1.2.9 I guess; or revise to work for when datadir changes. */
  334. /* This technically doesn't belong in the trunk, but it will be adapated for future use */
  335. static void conf_compat_pids()
  336. {
  337. conf_bot *bot = NULL;
  338. char path[DIRMAX] = "", dir[DIRMAX] = "";
  339. int i = 0;
  340. for (i = 0; i < 5; i++) {
  341. if (i == 0) {
  342. if (!conf.bot || !conf.bot->hub)
  343. simple_snprintf(dir, sizeof(dir), "%s/.ssh/...", conf.homedir);
  344. else
  345. simple_snprintf(dir, sizeof(dir), "%s/tmp", conf.binpath);
  346. } else if (i == 1) {
  347. simple_snprintf(dir, sizeof(dir), "/tmp");
  348. } else if (i == 2) {
  349. simple_snprintf(dir, sizeof(dir), "/usr/tmp");
  350. } else if (i == 3) {
  351. simple_snprintf(dir, sizeof(dir), "/var/tmp");
  352. } else if (i == 4) {
  353. simple_snprintf(dir, sizeof(dir), "%s", conf.binpath);
  354. }
  355. //Wait, we are checking for pids in our datadir? No thanks..
  356. if (!strcmp(conf.datadir, dir))
  357. continue;
  358. for (bot = conf.bots; bot && bot->nick; bot = bot->next)
  359. /* returns 1 if: pidfile is there and PID is running AND if there is a socksfile listed, if it is valid. */
  360. if (checkpid(bot->nick, bot, dir)) {
  361. /* Ok so we found a valid pid file, which might include a VALID socksfile. */
  362. simple_snprintf(path, sizeof(path), "%s/.pid.%s", conf.datadir, bot->nick);
  363. copyfile(bot->pid_file, path);
  364. //We only want to unlink if the pidfile is NOT being used, otherwise, it might break a bot that's on timer to restart/update.
  365. } else if (can_stat(bot->pid_file))
  366. unlink(bot->pid_file);
  367. }
  368. }
  369. void conf_checkpids()
  370. {
  371. conf_bot *bot = NULL;
  372. for (bot = conf.bots; bot && bot->nick; bot = bot->next)
  373. bot->pid = checkpid(bot->nick, bot, NULL);
  374. }
  375. /*
  376. * Return the PID of a bot if it is running, otherwise return 0
  377. */
  378. pid_t
  379. checkpid(const char *nick, conf_bot *bot, const char *usedir)
  380. {
  381. FILE *f = NULL;
  382. char buf[DIRMAX] = "", *tmpnick = NULL, *tmp_ptr = NULL;
  383. pid_t pid = 0;
  384. tmpnick = tmp_ptr = strdup(nick);
  385. /* FIXME: remove after 1.2.9 */
  386. if (usedir)
  387. simple_snprintf(buf, sizeof buf, "%s/.pid.%s", usedir, tmpnick);
  388. else
  389. simple_snprintf(buf, sizeof buf, "%s/.pid.%s", conf.datadir, tmpnick);
  390. free(tmp_ptr);
  391. if (bot && !(bot->pid_file))
  392. bot->pid_file = strdup(buf);
  393. else if (bot && strcmp(bot->pid_file, buf))
  394. str_redup(&bot->pid_file, buf);
  395. if ((f = fopen(buf, "r"))) {
  396. char *bufp = NULL, *pids = NULL;
  397. fgets(buf, sizeof(buf), f);
  398. fclose(f);
  399. remove_crlf(buf);
  400. if (!buf || !buf[0])
  401. return 0;
  402. bufp = buf;
  403. pids = newsplit(&bufp);
  404. if (str_isdigit(pids)) {
  405. pid = atoi(pids);
  406. if (kill(pid, SIGCHLD)) //Problem killing, most likely it's just not running.
  407. pid = 0;
  408. }
  409. //There is a socksfile given and it's accessable, plus the pid in the file is my own
  410. //So it's a good chance we just did a soft restart
  411. /* If this pidfile is stale, don't let compat_checkpids copy it over. */
  412. if (usedir && bufp[0] && pid) {
  413. if (can_stat(bufp))
  414. return pid;
  415. /* socks file not there? this pidfile is probably stale, move along ... */
  416. return 0;
  417. }
  418. if (bufp[0] && pid && can_stat(bufp) && (getpid() == pid) &&
  419. !egg_strncasecmp(nick, origbotname, HANDLEN)) {
  420. socksfile = strdup(bufp);
  421. return 0;
  422. }
  423. }
  424. return pid;
  425. }
  426. void
  427. conf_addbot(char *nick, char *ip, char *host, char *ip6)
  428. {
  429. conf_bot *bot = (conf_bot *) my_calloc(1, sizeof(conf_bot));
  430. bot->next = NULL;
  431. bot->pid_file = NULL;
  432. if (nick[0] == '/') {
  433. bot->disabled = 1;
  434. nick++;
  435. sdprintf("%s is disabled.", nick);
  436. }
  437. bot->nick = strldup(nick, HANDLEN);
  438. bot->net.ip = NULL;
  439. bot->net.host = NULL;
  440. bot->net.ip6 = NULL;
  441. bot->net.host6 = NULL;
  442. if (host && host[0] == '+') {
  443. host++;
  444. bot->net.host6 = strdup(host);
  445. } else if (host && strcmp(host, ".")) {
  446. bot->net.host = strdup(host);
  447. }
  448. if (ip && strcmp(ip, ".")) {
  449. int aftype = is_dotted_ip(ip);
  450. if (aftype == AF_INET)
  451. bot->net.ip = strdup(ip);
  452. #ifdef USE_IPV6
  453. else if (aftype == AF_INET6)
  454. bot->net.ip6 = strdup(ip);
  455. #endif /* USE_IPV6 */
  456. }
  457. #ifdef USE_IPV6
  458. if (ip6 && strcmp(ip6, ".") && is_dotted_ip(ip6) == AF_INET6)
  459. bot->net.ip6 = strdup(ip6);
  460. if (bot->net.ip6 || bot->net.host6)
  461. bot->net.v6 = 1;
  462. #endif /* USE_IPV6 */
  463. if (userlist)
  464. bot->u = get_user_by_handle(userlist, nick);
  465. else
  466. bot->u = NULL;
  467. // bot->pid = checkpid(nick, bot);
  468. if (settings.hubs) {
  469. char *p = settings.hubs, *p2 = NULL, hubbuf[HANDLEN + 1] ="";
  470. size_t len = 0;
  471. while (p && *p) {
  472. if ((p2 = strchr(p, ' '))) {
  473. len = p2 - p;
  474. simple_snprintf(hubbuf, len + 1, "%s", p);
  475. if (!egg_strncasecmp(bot->nick, hubbuf, HANDLEN)) {
  476. bot->hub = 1;
  477. break;
  478. }
  479. }
  480. if ((p = strchr(p, ',')))
  481. p++;
  482. }
  483. }
  484. /* not a hub
  485. AND
  486. * no bots added yet (first bot) yet, not disabled.
  487. OR
  488. * bots already listed but we dont have a localhub yet, so we're it!
  489. */
  490. if (!bot->hub && ((!conf.bots && !bot->disabled) || (conf.bots && !conf.localhub))) {
  491. bot->localhub = 1; /* first bot */
  492. conf.localhub = strdup(bot->nick);
  493. }
  494. list_append((struct list_type **) &(conf.bots), (struct list_type *) bot);
  495. }
  496. void
  497. free_bot(conf_bot *bot)
  498. {
  499. if (bot) {
  500. list_delete((struct list_type **) &(conf.bots), (struct list_type *) bot);
  501. free(bot->nick);
  502. free(bot->pid_file);
  503. if (bot->net.ip)
  504. free(bot->net.ip);
  505. if (bot->net.host)
  506. free(bot->net.host);
  507. if (bot->net.ip6)
  508. free(bot->net.ip6);
  509. if (bot->net.host6)
  510. free(bot->net.host6);
  511. free(bot);
  512. }
  513. }
  514. int
  515. conf_delbot(char *botn)
  516. {
  517. conf_bot *bot = NULL;
  518. for (bot = conf.bots; bot && bot->nick; bot = bot->next) {
  519. if (!strcmp(bot->nick, botn)) { /* found it! */
  520. bot->pid = checkpid(bot->nick, bot, NULL);
  521. conf_killbot(NULL, bot, SIGKILL);
  522. free_bot(bot);
  523. return 0;
  524. }
  525. }
  526. return 1;
  527. }
  528. void
  529. free_conf()
  530. {
  531. free_conf_bots(conf.bots);
  532. free_bot(conf.bot);
  533. conf.bot = NULL;
  534. if (conf.localhub)
  535. free(conf.localhub);
  536. if (conf.uname)
  537. free(conf.uname);
  538. if (conf.username)
  539. free(conf.username);
  540. if (conf.datadir)
  541. free(conf.datadir);
  542. if (conf.homedir)
  543. free(conf.homedir);
  544. if (conf.binname)
  545. free(conf.binname);
  546. if (conf.binpath)
  547. free(conf.binpath);
  548. init_conf();
  549. }
  550. void
  551. free_conf_bots(conf_bot *list)
  552. {
  553. if (list) {
  554. conf_bot *bot = NULL, *bot_n = NULL;
  555. for (bot = list; bot; bot = bot_n) {
  556. bot_n = bot->next;
  557. free_bot(bot);
  558. }
  559. list = NULL;
  560. }
  561. }
  562. void prep_homedir(bool error)
  563. {
  564. if (!conf.homedir)
  565. str_redup(&conf.homedir, homedir());
  566. if (error && (!conf.homedir || !conf.homedir[0]))
  567. werr(ERR_NOHOMEDIR);
  568. }
  569. int
  570. parseconf(bool error)
  571. {
  572. if (!conf.username)
  573. str_redup(&conf.username, my_username());
  574. if (error && (!conf.username || !conf.username[0]))
  575. werr(ERR_NOUSERNAME);
  576. #ifndef CYGWIN_HACKS
  577. if (error && conf.uid != (signed) myuid) {
  578. sdprintf("wrong uid, conf: %d :: %d", conf.uid, myuid);
  579. werr(ERR_WRONGUID);
  580. } else if (!conf.uid)
  581. conf.uid = myuid;
  582. if (conf.uname && strcmp(conf.uname, my_uname()) && !conf.autouname) {
  583. baduname(conf.uname, my_uname()); /* its not auto, and its not RIGHT, bail out. */
  584. sdprintf("wrong uname, conf: %s :: %s", conf.uname, my_uname());
  585. if (error)
  586. werr(ERR_WRONGUNAME);
  587. } else if (conf.uname && conf.autouname) { /* if autouname, dont bother comparing, just set uname to output */
  588. str_redup(&conf.uname, my_uname());
  589. } else if (!conf.uname) { /* if not set, then just set it, wont happen again next time... */
  590. conf.uname = strdup(my_uname());
  591. }
  592. #endif /* !CYGWIN_HACKS */
  593. return 0;
  594. }
  595. int
  596. readconf(const char *fname, int bits)
  597. {
  598. FILE *f = NULL;
  599. int i = 0, enc = (bits & CONF_ENC) ? 1 : 0;
  600. char *inbuf = NULL;
  601. sdprintf("readconf(%s, %d)", fname, enc);
  602. Context;
  603. if (!(f = fopen(fname, "r")))
  604. fatal("Cannot read config", 0);
  605. free_conf_bots(conf.bots);
  606. inbuf = (char *) my_calloc(1, 201);
  607. while (fgets(inbuf, 201, f) != NULL) {
  608. char *line = NULL, *temp_ptr = NULL;
  609. remove_crlf(inbuf);
  610. if (enc)
  611. line = temp_ptr = decrypt_string(settings.salt1, inbuf);
  612. else
  613. line = inbuf;
  614. if ((line && !line[0]) || line[0] == '\n') {
  615. if (enc)
  616. free(line);
  617. continue;
  618. }
  619. i++;
  620. rmspace(line);
  621. sdprintf("CONF LINE: %s", line);
  622. // !strchr("_`|}][{*/#-+!abcdefghijklmnopqrstuvwxyzABDEFGHIJKLMNOPWRSTUVWXYZ", line[0])) {
  623. if (enc && line[0] > '~') {
  624. sdprintf("line %d, char %c ", i, line[0]);
  625. fatal("Bad encryption", 0);
  626. } else { /* line is good to parse */
  627. /* - uid */
  628. if (line[0] == '-') {
  629. newsplit(&line);
  630. if (conf.uid == -1)
  631. conf.uid = atoi(line);
  632. /* + uname */
  633. } else if (line[0] == '+') {
  634. newsplit(&line);
  635. if (!conf.uname)
  636. conf.uname = strdup(line);
  637. /* ! is misc options */
  638. } else if (line[0] == '!') {
  639. char *option = NULL;
  640. newsplit(&line);
  641. if (line[0])
  642. option = newsplit(&line);
  643. if (!option || !line[0])
  644. continue;
  645. if (!strcmp(option, "autocron")) { /* automatically check/create crontab? */
  646. if (egg_isdigit(line[0]))
  647. conf.autocron = atoi(line);
  648. } else if (!strcmp(option, "autouname")) { /* auto update uname contents? */
  649. if (egg_isdigit(line[0]))
  650. conf.autouname = atoi(line);
  651. } else if (!strcmp(option, "username")) { /* shell username */
  652. str_redup(&conf.username, line);
  653. } else if (!strcmp(option, "homedir")) { /* homedir */
  654. str_redup(&conf.homedir, line);
  655. } else if (!strcmp(option, "datadir")) { /* datadir */
  656. str_redup(&conf.datadir, line);
  657. } else if (!strcmp(option, "binpath")) { /* path that the binary should move to? */
  658. str_redup(&conf.binpath, line);
  659. } else if (!strcmp(option, "binname")) { /* filename of the binary? */
  660. str_redup(&conf.binname, line);
  661. } else if (!strcmp(option, "portmin")) {
  662. if (egg_isdigit(line[0]))
  663. conf.portmin = atoi(line);
  664. } else if (!strcmp(option, "portmax")) {
  665. if (egg_isdigit(line[0]))
  666. conf.portmax = atoi(line);
  667. } else if (!strcmp(option, "pscloak")) { /* should bots on this shell pscloak? */
  668. if (egg_isdigit(line[0]))
  669. conf.pscloak = atoi(line);
  670. } else if (!strcmp(option, "uid")) { /* new method uid */
  671. if (str_isdigit(line))
  672. conf.uid = atoi(line);
  673. } else if (!strcmp(option, "uname")) { /* new method uname */
  674. str_redup(&conf.uname, line);
  675. } else if (!strcmp(option, "watcher")) {
  676. if (egg_isdigit(line[0]))
  677. conf.watcher = atoi(line);
  678. } else {
  679. putlog(LOG_MISC, "*", "Unrecognized config option '%s'", option);
  680. }
  681. /* read in portmin */
  682. } else if (line[0] == '>') {
  683. newsplit(&line);
  684. conf.portmin = atoi(line);
  685. } else if (line[0] == '<') {
  686. newsplit(&line);
  687. conf.portmax = atoi(line);
  688. /* now to parse nick/hosts */
  689. } else if (line[0] != '#') {
  690. char *nick = NULL, *host = NULL, *ip = NULL, *ipsix = NULL;
  691. nick = newsplit(&line);
  692. if (!nick || (nick && !nick[0]))
  693. werr(ERR_BADCONF);
  694. if (line[0])
  695. ip = newsplit(&line);
  696. if (line[0])
  697. host = newsplit(&line);
  698. if (line[0])
  699. ipsix = newsplit(&line);
  700. conf_addbot(nick, ip, host, ipsix);
  701. }
  702. }
  703. inbuf[0] = 0;
  704. if (enc)
  705. free(temp_ptr);
  706. } /* while(fgets()) */
  707. fclose(f);
  708. free(inbuf);
  709. return 0;
  710. }
  711. int
  712. writeconf(char *filename, FILE * stream, int bits)
  713. {
  714. FILE *f = NULL;
  715. conf_bot *bot = NULL;
  716. int (*my_write) (FILE *, const char *, ... ) = NULL;
  717. int autowrote = 0;
  718. if (bits & CONF_ENC)
  719. my_write = lfprintf;
  720. else if (!(bits & CONF_ENC))
  721. my_write = fprintf;
  722. #define comment(text) do { \
  723. if (bits & CONF_COMMENT) \
  724. my_write(f, "%s\n", text); \
  725. } while(0)
  726. if (stream) {
  727. f = stream;
  728. } else if (filename) {
  729. if (!(f = fopen(filename, "w")))
  730. return 1;
  731. }
  732. #ifndef CYGWIN_HACKS
  733. char *p = NULL;
  734. comment("# Lines beginning with # are what the preceeding line SHOULD be");
  735. comment("# They are simply comments and are not parsed at all.\n");
  736. #define conf_com() do { \
  737. if (do_confedit == CONF_AUTO) { \
  738. comment("# Automatically updated with -C"); \
  739. autowrote = 1; \
  740. } else \
  741. comment("#The correct line follows. (Not auto due to -c)"); \
  742. } while(0)
  743. if ((bits & CONF_COMMENT) && conf.uid != (signed) myuid) {
  744. conf_com();
  745. my_write(f, "%s! uid %d\n", do_confedit == CONF_AUTO ? "" : "#", myuid);
  746. my_write(f, "%s! uid %d\n", do_confedit == CONF_STATIC ? "" : "#", conf.uid);
  747. } else
  748. my_write(f, "! uid %d\n", conf.uid);
  749. if (!conf.uname || (conf.uname && conf.autouname && strcmp(conf.uname, my_uname()))) {
  750. autowrote = 1;
  751. if (conf.uname)
  752. comment("# autouname is ON");
  753. else
  754. comment("# Automatically updated empty uname");
  755. my_write(f, "! uname %s\n", my_uname());
  756. if (conf.uname)
  757. my_write(f, "#! uname %s\n", conf.uname);
  758. } else if (conf.uname && !conf.autouname && strcmp(conf.uname, my_uname())) {
  759. conf_com();
  760. my_write(f, "%s! uname %s\n", do_confedit == CONF_AUTO ? "" : "#", my_uname());
  761. my_write(f, "%s! uname %s\n", do_confedit == CONF_STATIC ? "" : "#", conf.uname);
  762. } else
  763. my_write(f, "! uname %s\n", conf.uname);
  764. comment("");
  765. if (conf.username && my_username() && strcmp(conf.username, my_username())) {
  766. conf_com();
  767. my_write(f, "%s! username %s\n", do_confedit == CONF_AUTO ? "" : "#", my_username());
  768. my_write(f, "%s! username %s\n", do_confedit == CONF_STATIC ? "" : "#", conf.username);
  769. } else
  770. my_write(f, "! username %s\n", conf.username ? conf.username : my_username() ? my_username() : "");
  771. if (conf.homedir && homedir(0) && strcmp(conf.homedir, homedir(0))) {
  772. conf_com();
  773. my_write(f, "%s! homedir %s\n", do_confedit == CONF_AUTO ? "" : "#", homedir(0));
  774. my_write(f, "%s! homedir %s\n", do_confedit == CONF_STATIC ? "" : "#", conf.homedir);
  775. } else
  776. my_write(f, "! homedir %s\n", conf.homedir ? conf.homedir : homedir(0) ? homedir(0) : "");
  777. comment("\n# binpath needs to be full path unless it begins with '~', which uses 'homedir', ie, '~/'");
  778. if (homedir() && strstr(conf.binpath, homedir())) {
  779. p = replace(conf.binpath, homedir(), "~");
  780. my_write(f, "! binpath %s\n", p);
  781. } else
  782. my_write(f, "! binpath %s\n", conf.binpath);
  783. comment("# binname is relative to binpath, if you change this, you'll need to manually remove the old one from crontab.");
  784. my_write(f, "! binname %s\n", conf.binname);
  785. comment("");
  786. comment("# datadir should be set to a static directory that is writable");
  787. if (homedir() && strstr(conf.datadir, homedir())) {
  788. p = replace(conf.datadir, homedir(), "~");
  789. my_write(f, "! datadir %s\n", p);
  790. } else
  791. my_write(f, "! datadir %s\n", conf.datadir);
  792. comment("");
  793. comment("# portmin/max are for incoming connections (DCC) [0 for any]");
  794. my_write(f, "! portmin %d\n", conf.portmin);
  795. my_write(f, "! portmax %d\n", conf.portmax);
  796. comment("");
  797. comment("# Attempt to \"cloak\" the process name in `ps` for Linux?");
  798. my_write(f, "! pscloak %d\n", conf.pscloak);
  799. comment("");
  800. comment("# Automatically add the bot to crontab? (Disable if binname has funky chars that need escaping)");
  801. my_write(f, "! autocron %d\n", conf.autocron);
  802. comment("");
  803. comment("# Automatically update 'uname' if it changes? (DANGEROUS)");
  804. my_write(f, "! autouname %d\n", conf.autouname);
  805. comment("");
  806. #ifdef NO
  807. comment("# This will spawn a child process for EACH BOT that will block ALL process hijackers.");
  808. my_write(f, "! watcher %d\n", conf.watcher);
  809. comment("");
  810. #endif
  811. comment("# '|' means OR, [] means the enclosed is optional");
  812. comment("# A '+' in front of HOST means the HOST is ipv6");
  813. comment("# A '/' in front of BOT will disable that bot.");
  814. comment("#[/]BOT IP|. [+]HOST|. [IPV6-IP]");
  815. comment("#***** 1.2.3: Hubs CAN be mixed with leaf bots, but is not fully tested; it is not recommended. ******");
  816. #endif /* CYGWIN_HACKS */
  817. for (bot = conf.bots; bot && bot->nick; bot = bot->next) {
  818. my_write(f, "%s%s %s %s%s %s\n",
  819. bot->disabled ? "/" : "", bot->nick,
  820. bot->net.ip ? bot->net.ip : ".", bot->net.host6 ? "+" : "",
  821. bot->net.host ? bot->net.host : (bot->net.host6 ? bot->net.host6 : "."), bot->net.ip6 ? bot->net.ip6 : "");
  822. }
  823. fflush(f);
  824. if (!stream)
  825. fclose(f);
  826. return autowrote;
  827. }
  828. static void
  829. conf_bot_dup(conf_bot *dest, conf_bot *src)
  830. {
  831. if (dest && src) {
  832. dest->nick = src->nick ? strdup(src->nick) : NULL;
  833. dest->pid_file = src->pid_file ? strdup(src->pid_file) : NULL;
  834. dest->net.ip = src->net.ip ? strdup(src->net.ip) : NULL;
  835. dest->net.host = src->net.host ? strdup(src->net.host) : NULL;
  836. dest->net.ip6 = src->net.ip6 ? strdup(src->net.ip6) : NULL;
  837. dest->net.host6 = src->net.host6 ? strdup(src->net.host6) : NULL;
  838. dest->net.v6 = src->net.v6;
  839. dest->u = src->u ? src->u : NULL;
  840. dest->pid = src->pid;
  841. dest->hub = src->hub;
  842. dest->localhub = src->localhub;
  843. dest->disabled = src->disabled;
  844. dest->next = NULL;
  845. }
  846. }
  847. conf_bot *conf_bots_dup(conf_bot *src)
  848. {
  849. conf_bot *ret = NULL;
  850. if (src) {
  851. conf_bot *bot = NULL, *newbot = NULL;
  852. for (bot = src; bot && bot->nick; bot = bot->next) {
  853. newbot = (conf_bot *) my_calloc(1, sizeof(conf_bot));
  854. conf_bot_dup(newbot, bot);
  855. list_append((struct list_type **) &(ret), (struct list_type *) newbot);
  856. }
  857. }
  858. return ret;
  859. }
  860. void kill_removed_bots(conf_bot *oldlist, conf_bot *newlist)
  861. {
  862. if (oldlist) {
  863. conf_bot *botold = NULL, *botnew = NULL;
  864. bool found = 0;
  865. struct userrec *u = NULL;
  866. for (botold = oldlist; botold && botold->nick; botold = botold->next) {
  867. found = 0;
  868. for (botnew = newlist; botnew && botnew->nick; botnew = botnew->next) {
  869. if (!egg_strcasecmp(botold->nick, botnew->nick)) {
  870. found = 1;
  871. break;
  872. }
  873. }
  874. if (!found) {
  875. conf_killbot(NULL, botold, SIGKILL);
  876. if ((u = get_user_by_handle(userlist, botold->nick))) {
  877. putlog(LOG_MISC, "*", "Removing '%s' as it has been removed from the binary config.", botold->nick);
  878. if (server_online)
  879. check_this_user(botold->nick, 1, NULL);
  880. if (deluser(botold->nick)) {
  881. /* there is likely NO conf[]
  882. if (conf.bot->hub)
  883. write_userfile(-1);
  884. */
  885. }
  886. }
  887. }
  888. }
  889. }
  890. }
  891. void
  892. fill_conf_bot()
  893. {
  894. if (!conf.bots || !conf.bots->nick)
  895. return;
  896. char *mynick = NULL;
  897. conf_bot *me = NULL;
  898. /* This first clause should actually be obsolete */
  899. if (!used_B && conf.bots && conf.bots->nick) {
  900. mynick = strdup(conf.bots->nick);
  901. strlcpy(origbotname, conf.bots->nick, HANDLEN + 1);
  902. } else
  903. mynick = strldup(origbotname, HANDLEN);
  904. sdprintf("mynick: %s", mynick);
  905. for (me = conf.bots; me && me->nick; me = me->next)
  906. if (!egg_strcasecmp(me->nick, mynick))
  907. break;
  908. if (!me || (me->nick && egg_strcasecmp(me->nick, mynick)))
  909. werr(ERR_BADBOT);
  910. free(mynick);
  911. /* for future, we may just want to make this a pointer to ->bots if we do an emech style currentbot-> */
  912. conf.bot = (conf_bot *) my_calloc(1, sizeof(conf_bot));
  913. conf_bot_dup(conf.bot, me);
  914. }
  915. void
  916. bin_to_conf(bool error)
  917. {
  918. /* printf("Converting binary data to conf struct\n"); */
  919. conf.uid = atol(settings.uid);
  920. if (settings.username[0])
  921. str_redup(&conf.username, settings.username);
  922. str_redup(&conf.uname, settings.uname);
  923. str_redup(&conf.datadir, settings.datadir);
  924. if (settings.homedir[0])
  925. str_redup(&conf.homedir, settings.homedir);
  926. str_redup(&conf.binpath, settings.binpath);
  927. str_redup(&conf.binname, settings.binname);
  928. conf.portmin = atol(settings.portmin);
  929. conf.portmax = atol(settings.portmax);
  930. conf.autouname = atoi(settings.autouname);
  931. conf.autocron = atoi(settings.autocron);
  932. conf.watcher = atoi(settings.watcher);
  933. conf.pscloak = atoi(settings.pscloak);
  934. prep_homedir(error);
  935. expand_tilde(&conf.datadir);
  936. expand_tilde(&conf.binpath);
  937. /* PARSE/ADD BOTS */
  938. {
  939. char *p = NULL, *tmp = NULL, *tmpp = NULL;
  940. tmp = tmpp = strdup(settings.bots);
  941. while ((p = strchr(tmp, ','))) {
  942. char *nick = NULL, *host = NULL, *ip = NULL, *ipsix = NULL;
  943. *p++ = 0;
  944. if (!tmp[0])
  945. break;
  946. nick = newsplit(&tmp);
  947. if (!nick || (nick && !nick[0]))
  948. werr(ERR_BADCONF);
  949. if (tmp[0])
  950. ip = newsplit(&tmp);
  951. if (tmp[0])
  952. host = newsplit(&tmp);
  953. if (tmp[0])
  954. ipsix = newsplit(&tmp);
  955. conf_addbot(nick, ip, host, ipsix);
  956. tmp = p++;
  957. }
  958. free(tmpp);
  959. }
  960. mkdir_p(conf.datadir);
  961. Tempfile::FindDir();
  962. if (clear_tmpdir)
  963. clear_tmp(); /* clear out the tmp dir, no matter if we are localhub or not */
  964. conf_compat_pids();
  965. conf_checkpids();
  966. tellconf();
  967. }
  968. void conf_add_userlist_bots()
  969. {
  970. conf_bot *bot = NULL;
  971. struct userrec *u = NULL;
  972. struct bot_addr *bi = NULL;
  973. char tmp[81] = "", uhost[UHOSTLEN] = "";
  974. for (bot = conf.bots; bot && bot->nick; bot = bot->next) {
  975. /* Don't auto-add hubs. */
  976. if (!bot->hub) {
  977. u = get_user_by_handle(userlist, bot->nick);
  978. if (!u) {
  979. putlog(LOG_MISC, "*", "Adding bot '%s' as it has been added to the binary config.", bot->nick);
  980. userlist = adduser(userlist, bot->nick, "none", "-", USER_OP, 1);
  981. u = get_user_by_handle(userlist, bot->nick);
  982. egg_snprintf(tmp, sizeof(tmp), "%li [internal]", now);
  983. set_user(&USERENTRY_ADDED, u, tmp);
  984. bi = (struct bot_addr *) my_calloc(1, sizeof(struct bot_addr));
  985. bi->address = (char *) my_calloc(1, 1);
  986. bi->uplink = (char *) my_calloc(1, 1);
  987. bi->telnet_port = bi->relay_port = 3333;
  988. bi->hublevel = 999;
  989. set_user(&USERENTRY_BOTADDR, u, bi);
  990. }
  991. if (bot->net.ip) {
  992. simple_snprintf(uhost, sizeof(uhost), "*!%s@%s", conf.username, bot->net.ip);
  993. if (!user_has_host(NULL, u, uhost) && !host_conflicts(uhost))
  994. addhost_by_handle(bot->nick, uhost);
  995. simple_snprintf(uhost, sizeof(uhost), "*!~%s@%s", bot->nick, bot->net.ip);
  996. if (!user_has_host(NULL, u, uhost) && !host_conflicts(uhost))
  997. addhost_by_handle(bot->nick, uhost);
  998. }
  999. if (bot->net.host) {
  1000. simple_snprintf(uhost, sizeof(uhost), "*!%s@%s", conf.username, bot->net.host);
  1001. if (!user_has_host(NULL, u, uhost) && !host_conflicts(uhost))
  1002. addhost_by_handle(bot->nick, uhost);
  1003. }
  1004. if (bot->net.host6) {
  1005. simple_snprintf(uhost, sizeof(uhost), "*!%s@%s", conf.username, bot->net.host6);
  1006. if (!user_has_host(NULL, u, uhost) && !host_conflicts(uhost))
  1007. addhost_by_handle(bot->nick, uhost);
  1008. }
  1009. if (bot->net.ip6) {
  1010. simple_snprintf(uhost, sizeof(uhost), "*!%s@%s", conf.username, bot->net.ip6);
  1011. if (!user_has_host(NULL, u, uhost) && !host_conflicts(uhost))
  1012. addhost_by_handle(bot->nick, uhost);
  1013. }
  1014. }
  1015. }
  1016. }