pure-authd.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. #include <config.h>
  2. #ifndef WITH_EXTAUTH
  3. #include <stdio.h>
  4. int main(void)
  5. {
  6. puts("Please compile the server with --with-extauth to use this feature.\n"
  7. "Thank you.");
  8. return 0;
  9. }
  10. #else
  11. #include "ftpd.h"
  12. #include "log_extauth.h"
  13. #include "pure-authd_p.h"
  14. #include "safe_rw.h"
  15. #ifdef WITH_DMALLOC
  16. # include <dmalloc.h>
  17. #endif
  18. static void setcloexec(const int fd)
  19. {
  20. fcntl(fd, F_SETFD, FD_CLOEXEC);
  21. }
  22. static int closedesc_all(const int closestdin)
  23. {
  24. int fodder;
  25. if (closestdin != 0) {
  26. (void) close(0);
  27. if ((fodder = open("/dev/null", O_RDONLY)) == -1) {
  28. return -1;
  29. }
  30. (void) dup2(fodder, 0);
  31. if (fodder > 0) {
  32. (void) close(fodder);
  33. }
  34. }
  35. if ((fodder = open("/dev/null", O_WRONLY)) == -1) {
  36. return -1;
  37. }
  38. (void) dup2(fodder, 1);
  39. (void) dup2(1, 2);
  40. if (fodder > 2) {
  41. (void) close(fodder);
  42. }
  43. return 0;
  44. }
  45. static void dodaemonize(void)
  46. {
  47. pid_t child;
  48. if (daemonize != 0) {
  49. if ((child = fork()) == (pid_t) -1) {
  50. perror("Daemonization failed - fork");
  51. return;
  52. } else if (child != (pid_t) 0) {
  53. _exit(EXIT_SUCCESS);
  54. } else if (setsid() == (pid_t) -1) {
  55. perror("Daemonization failed : setsid");
  56. }
  57. (void) chdir("/");
  58. #ifdef HAVE_CLOSEFROM
  59. (void) closefrom(3);
  60. #endif
  61. (void) closedesc_all(1);
  62. }
  63. }
  64. static int init(void)
  65. {
  66. #ifndef NON_ROOT_FTP
  67. if (geteuid() != (uid_t) 0) {
  68. fprintf(stderr,
  69. "Sorry, but you have to be root to run this program\n");
  70. return -1;
  71. }
  72. #endif
  73. return 0;
  74. }
  75. static void usage(void)
  76. {
  77. #ifndef NO_GETOPT_LONG
  78. const struct option *options = long_options;
  79. do {
  80. printf("-%c\t--%s\t%s\n", options->val, options->name,
  81. options->has_arg ? "<opt>" : "");
  82. options++;
  83. } while (options->name != NULL);
  84. #endif
  85. exit(EXIT_SUCCESS);
  86. }
  87. static int parseoptions(int argc, char *argv[])
  88. {
  89. #ifndef NO_GETOPT_LONG
  90. int option_index = 0;
  91. #endif
  92. int fodder;
  93. while ((fodder =
  94. #ifndef NO_GETOPT_LONG
  95. getopt_long(argc, argv, GETOPT_OPTIONS, long_options,
  96. &option_index)
  97. #else
  98. getopt(argc, argv, GETOPT_OPTIONS)
  99. #endif
  100. ) != -1) {
  101. switch (fodder) {
  102. case 'B': {
  103. daemonize = 1;
  104. break;
  105. }
  106. case 'g': {
  107. const char *nptr;
  108. char *endptr;
  109. nptr = optarg;
  110. endptr = NULL;
  111. gid = (gid_t) strtoul(nptr, &endptr, 10);
  112. if (!nptr || !*nptr || !endptr || *endptr) {
  113. perror("Illegal GID - Must be a number\n");
  114. }
  115. break;
  116. }
  117. case 'p': {
  118. if ((authd_pid_file = strdup(optarg)) == NULL) {
  119. perror("Oh no ! More memory !");
  120. }
  121. break;
  122. }
  123. #ifndef NO_GETOPT_LONG
  124. case 'h': {
  125. usage();
  126. }
  127. #endif
  128. case 'r': {
  129. if (script == NULL && (script = strdup(optarg)) == NULL) {
  130. perror("Oh no ! More memory !");
  131. }
  132. break;
  133. }
  134. case 's': {
  135. if (socketpath == NULL && (socketpath = strdup(optarg)) == NULL) {
  136. perror("Oh no ! More memory !");
  137. }
  138. break;
  139. }
  140. case 'u': {
  141. const char *nptr;
  142. char *endptr;
  143. nptr = optarg;
  144. endptr = NULL;
  145. uid = (uid_t) strtoul(nptr, &endptr, 10);
  146. if (!*nptr || !endptr || *endptr) {
  147. perror("Illegal UID - Must be a number\n");
  148. }
  149. break;
  150. }
  151. default:
  152. usage();
  153. }
  154. }
  155. return 0;
  156. }
  157. static int changeuidgid(void)
  158. {
  159. #ifndef NON_ROOT_FTP
  160. if (
  161. # ifdef HAVE_SETGROUPS
  162. setgroups(1U, &gid) ||
  163. # endif
  164. setgid(gid) || setegid(gid) ||
  165. setuid(uid) || seteuid(uid) || chdir("/")) {
  166. return -1;
  167. }
  168. #endif
  169. return 0;
  170. }
  171. static void newenv_str(const char * const var, const char * const str)
  172. {
  173. size_t s;
  174. char *v;
  175. if (str == NULL || *str == 0) {
  176. return;
  177. }
  178. s = strlen(var) + strlen(str) + (size_t) 2U;
  179. if ((v = malloc(s)) == NULL) {
  180. return;
  181. }
  182. if (SNCHECK(snprintf(v, s, "%s=%s", var, str), s)) {
  183. free(v);
  184. return;
  185. }
  186. #ifdef HAVE_PUTENV
  187. putenv(v);
  188. #endif
  189. }
  190. static void updatepidfile(void)
  191. {
  192. int fd;
  193. char buf[42];
  194. size_t buf_len;
  195. if (SNCHECK(snprintf(buf, sizeof buf, "%lu\n",
  196. (unsigned long) getpid()), sizeof buf)) {
  197. return;
  198. }
  199. if (unlink(authd_pid_file) != 0 && errno != ENOENT) {
  200. return;
  201. }
  202. if ((fd = open(authd_pid_file, O_CREAT | O_WRONLY | O_TRUNC |
  203. O_NOFOLLOW, (mode_t) 0644)) == -1) {
  204. return;
  205. }
  206. buf_len = strlen(buf);
  207. if (safe_write(fd, buf, buf_len, -1) != (ssize_t) buf_len) {
  208. ftruncate(fd, (off_t) 0);
  209. }
  210. close(fd);
  211. }
  212. static void callback_client_account(const char *str)
  213. {
  214. newenv_str(ENV_AUTHD_ACCOUNT, str);
  215. }
  216. static void callback_client_password(const char *str)
  217. {
  218. newenv_str(ENV_AUTHD_PASSWORD, str);
  219. }
  220. static void callback_client_sa_host(const char *str)
  221. {
  222. newenv_str(ENV_AUTHD_SA_HOST, str);
  223. }
  224. static void callback_client_sa_port(const char *str)
  225. {
  226. newenv_str(ENV_AUTHD_SA_PORT, str);
  227. }
  228. static void callback_client_peer_host(const char *str)
  229. {
  230. newenv_str(ENV_AUTHD_PEER_HOST, str);
  231. }
  232. static void callback_client_encrypted(const char *str)
  233. {
  234. newenv_str(ENV_AUTHD_ENCRYPTED, str);
  235. }
  236. static void callback_client_sni_name(const char *str)
  237. {
  238. if (*str != 0) {
  239. newenv_str(ENV_AUTHD_CLIENT_SNI_NAME, str);
  240. }
  241. }
  242. static void callback_client_end(const char *str)
  243. {
  244. (void) str;
  245. ended = 1;
  246. }
  247. static void process(const int clientfd)
  248. {
  249. ssize_t readnb;
  250. char *linepnt;
  251. char *crpoint;
  252. pid_t pid;
  253. int pfds[2];
  254. char line[4096];
  255. while ((readnb = read(clientfd, line, sizeof line - 1U)) < (ssize_t) 0 &&
  256. (errno == EINTR || errno == EIO));
  257. if (readnb <= (ssize_t) 0) {
  258. return;
  259. }
  260. line[readnb] = 0;
  261. if (pipe(pfds) != 0) {
  262. return;
  263. }
  264. pid = fork();
  265. if (pid == (pid_t) -1) {
  266. close(pfds[0]);
  267. close(pfds[1]);
  268. return;
  269. }
  270. if (pid != (pid_t) 0) {
  271. close(pfds[1]); /* close the output side of the pipe */
  272. if ((readnb = safe_read(pfds[0], line,
  273. sizeof line - 1U)) > (ssize_t) 0) {
  274. (void) safe_write(clientfd, line, readnb, -1);
  275. }
  276. #ifdef HAVE_WAITPID
  277. (void) waitpid(pid, NULL, 0);
  278. #else
  279. while (wait3(NULL, 0, NULL) != pid);
  280. #endif
  281. close(pfds[0]);
  282. return;
  283. }
  284. /* now, we are in the child */
  285. close(clientfd);
  286. close(kindy);
  287. close(pfds[0]); /* close the input side of the pipe */
  288. closedesc_all(1);
  289. linepnt = line;
  290. while ((crpoint = strchr(linepnt, '\n')) != NULL) {
  291. const ExtauthdCallBack *scanned;
  292. size_t keyword_len;
  293. *crpoint = 0;
  294. scanned = extauthd_callbacks;
  295. while (scanned->keyword != NULL) {
  296. keyword_len = strlen(scanned->keyword);
  297. if (strncmp(scanned->keyword, linepnt, keyword_len) == 0) {
  298. scanned->func(linepnt + keyword_len);
  299. break;
  300. }
  301. scanned++;
  302. }
  303. linepnt = crpoint + 1;
  304. }
  305. if (ended == 0) {
  306. close(pfds[1]);
  307. _exit(EXIT_FAILURE);
  308. }
  309. if (dup2(pfds[1], 1) == -1) {
  310. close(pfds[1]);
  311. _exit(EXIT_FAILURE);
  312. }
  313. close(pfds[1]);
  314. #ifdef DO_AUTHD_TIMEOUT
  315. (void) alarm(AUTHD_SCRIPT_TIMEOUT);
  316. #endif
  317. (void) execl(script, script, (char *) NULL);
  318. _exit(EXIT_SUCCESS);
  319. }
  320. int listencnx(void)
  321. {
  322. struct sockaddr_un *saddr;
  323. int clientfd;
  324. int ret = -1;
  325. const size_t socketpath_len = strlen(socketpath);
  326. if ((saddr = malloc(sizeof(*saddr) + socketpath_len +
  327. (size_t) 1U)) == NULL) {
  328. perror("No more memory to listen to anything");
  329. goto bye;
  330. }
  331. memcpy(saddr->sun_path, socketpath, socketpath_len + (size_t) 1U);
  332. saddr->sun_family = AF_UNIX;
  333. (void) unlink(socketpath);
  334. (void) umask(077);
  335. if ((kindy = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
  336. perror("Unable to create a local socket");
  337. goto bye;
  338. }
  339. setcloexec(kindy);
  340. if (bind(kindy, (struct sockaddr *) saddr, SUN_LEN(saddr)) != 0) {
  341. perror("Unable to bind a local socket");
  342. goto bye;
  343. }
  344. if (chmod(socketpath, 0600) != 0) {
  345. perror("Unable to change perms on the local socket");
  346. goto bye;
  347. }
  348. if (listen(kindy, AUTHD_BACKLOG) != 0) {
  349. perror("Unable to listen the local socket");
  350. goto bye;
  351. }
  352. if (changeuidgid() < 0) {
  353. perror("Identity change");
  354. (void) unlink(authd_pid_file);
  355. return -1;
  356. }
  357. do {
  358. if ((clientfd = accept(kindy, NULL, NULL)) == -1) {
  359. if (exit_authd != 0) {
  360. break;
  361. }
  362. (void) sleep(1);
  363. continue;
  364. }
  365. setcloexec(clientfd);
  366. process(clientfd);
  367. close(clientfd);
  368. } while (exit_authd == 0);
  369. ret = 0;
  370. bye:
  371. if (kindy != -1) {
  372. close(kindy);
  373. kindy = -1;
  374. }
  375. (void) unlink(socketpath);
  376. free(saddr);
  377. return ret;
  378. }
  379. static RETSIGTYPE sigterm(int sig)
  380. {
  381. (void) sig;
  382. exit_authd = 1;
  383. if (kindy != -1) {
  384. close(kindy);
  385. kindy = -1;
  386. }
  387. }
  388. int main(int argc, char *argv[])
  389. {
  390. int err;
  391. #ifdef HAVE_SETLOCALE
  392. # ifdef LC_MESSAGES
  393. (void) setlocale(LC_MESSAGES, "");
  394. # endif
  395. # ifdef LC_CTYPE
  396. (void) setlocale(LC_CTYPE, "");
  397. # endif
  398. # ifdef LC_COLLATE
  399. (void) setlocale(LC_COLLATE, "");
  400. # endif
  401. #endif
  402. if (init() < 0) {
  403. return -1;
  404. }
  405. (void) signal(SIGTERM, sigterm);
  406. (void) signal(SIGQUIT, sigterm);
  407. (void) signal(SIGINT, sigterm);
  408. #ifdef SIGXCPU
  409. (void) signal(SIGXCPU, sigterm);
  410. #endif
  411. if (parseoptions(argc, argv) < 0) {
  412. return -1;
  413. }
  414. if (script == NULL || *script != '/') {
  415. fprintf(stderr, "You must give -r /path/to/auth/program\n");
  416. return -2;
  417. }
  418. if (socketpath == NULL || *socketpath == 0) {
  419. fprintf(stderr, "You must give -s /path/to/socket\n");
  420. return -2;
  421. }
  422. if (daemonize != 0) {
  423. dodaemonize();
  424. }
  425. updatepidfile();
  426. #ifdef SIGPIPE
  427. signal(SIGPIPE, SIG_IGN);
  428. #endif
  429. #ifdef SIGCHLD
  430. signal(SIGCHLD, SIG_DFL);
  431. #endif
  432. err = listencnx();
  433. (void) unlink(authd_pid_file);
  434. return err;
  435. }
  436. #endif