mcserv.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407
  1. /* Server for the Midnight Commander Virtual File System.
  2. Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
  3. 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
  4. Written by:
  5. Miguel de Icaza, 1995, 1997,
  6. Andrej Borsenkow 1996.
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or
  10. (at your option) any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18. */
  19. /**
  20. * \file
  21. * \brief Source: server for the Midnight Commander Virtual File System
  22. * \author Miguel de Icaza
  23. * \author Andrej Borsenkow
  24. * \date 1995, 1996, 1997
  25. *
  26. * \todo opendir instead of keeping its table of file handles could return
  27. * the pointer and expect the client to send a proper value back each
  28. * time :-) We should use syslog to register login/logout.
  29. */
  30. /* {{{ Includes and global variables */
  31. #include <config.h>
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <unistd.h>
  35. #include <string.h>
  36. #include <fcntl.h>
  37. #ifdef HAVE_LIMITS_H
  38. # include <limits.h>
  39. #endif
  40. #ifndef NGROUPS_MAX
  41. # include <sys/param.h>
  42. # ifdef NGROUPS
  43. # define NGROUPS_MAX NGROUPS
  44. # endif
  45. #endif
  46. #include <grp.h>
  47. #include <sys/types.h>
  48. #include <sys/stat.h>
  49. #include <sys/wait.h>
  50. #include <error.h>
  51. #include <errno.h>
  52. #include <signal.h>
  53. #ifdef HAVE_GETOPT_H
  54. # include <getopt.h>
  55. #endif
  56. /* Network include files */
  57. #include <sys/socket.h>
  58. #include <netinet/in.h>
  59. #include <netdb.h>
  60. #ifdef HAVE_ARPA_INET_H
  61. #include <arpa/inet.h>
  62. #endif
  63. #ifdef HAVE_PMAP_SET
  64. # include <rpc/rpc.h>
  65. # include <rpc/pmap_prot.h>
  66. # ifdef HAVE_RPC_PMAP_CLNT_H
  67. # include <rpc/pmap_clnt.h>
  68. # endif
  69. #endif
  70. #if defined(HAVE_PAM)
  71. # if !defined(HAVE_SECURITY_PAM_MISC_H)
  72. # undef HAVE_PAM
  73. # endif
  74. #endif
  75. /* Authentication include files */
  76. #include <pwd.h>
  77. #ifdef HAVE_PAM
  78. # include <security/pam_misc.h>
  79. # ifndef PAM_ESTABLISH_CRED
  80. # define PAM_ESTABLISH_CRED PAM_CRED_ESTABLISH
  81. # endif
  82. #else
  83. #endif /* !HAVE_PAM */
  84. #ifdef HAVE_CRYPT_H
  85. # include <crypt.h>
  86. #endif /* !HAVE_CRYPT_H */
  87. #ifdef HAVE_SHADOW_H
  88. # include <shadow.h>
  89. #else
  90. # ifdef HAVE_SHADOW_SHADOW_H
  91. # include <shadow/shadow.h>
  92. # endif
  93. #endif
  94. /*
  95. * GNU gettext defines printf to libintl_printf on platforms that lack
  96. * a native printf(3) capable of all POSIX features.
  97. */
  98. #undef ENABLE_NLS
  99. #include "lib/global.h"
  100. #include "src/wtools.h" /* message() */
  101. #include "src/main.h" /* print_vfs_message */
  102. #include "utilvfs.h"
  103. #include "vfs.h"
  104. #include "mcfs.h"
  105. #include "mcfsutil.h"
  106. #include "netutil.h"
  107. #ifndef INADDR_NONE
  108. # define INADDR_NONE (0xffffffffU)
  109. #endif
  110. /* replacement for g_free() from glib */
  111. #undef g_free
  112. #define g_free(x) do {if (x) free (x);} while (0)
  113. /* We don't care about SIGPIPE */
  114. int got_sigpipe = 0;
  115. /* The socket from which we accept commands */
  116. int msock;
  117. /* Requested version number from client */
  118. static int clnt_version;
  119. /* If non zero, we accept further commands */
  120. int logged_in = 0;
  121. /* Home directory */
  122. const char *home_dir = NULL;
  123. char *up_dir = NULL;
  124. /* Were we started from inetd? */
  125. int inetd_started = 0;
  126. /* Are we running as a daemon? */
  127. int isDaemon = 0;
  128. /* guess */
  129. int verbose = 0;
  130. /* ftp auth */
  131. int ftp = 0;
  132. /* port number in which we listen to connections,
  133. * if zero, we try to contact the portmapper to get a port, and
  134. * if it's not possible, then we use a hardcoded value
  135. */
  136. int portnum = 0;
  137. /* if the server will use rcmd based authentication (hosts.equiv .rhosts) */
  138. int r_auth = 0;
  139. #define OPENDIR_HANDLES 8
  140. #define DO_QUIT_VOID() \
  141. do { \
  142. quit_server = 1; \
  143. return_code = 1; \
  144. return; \
  145. } while (0)
  146. /* Only used by get_port_number */
  147. #define DO_QUIT_NONVOID(a) \
  148. do { \
  149. quit_server = 1; \
  150. return_code = 1; \
  151. return (a); \
  152. } while (0)
  153. char buffer[4096];
  154. int debug = 1;
  155. static int quit_server;
  156. static int return_code;
  157. /* }}} */
  158. /* {{{ Misc routines */
  159. static void
  160. send_status (int status, int errno_number)
  161. {
  162. rpc_send (msock, RPC_INT, status, RPC_INT, errno_number, RPC_END);
  163. errno = 0;
  164. }
  165. /* }}} */
  166. /* {{{ File with handle operations */
  167. static void
  168. do_open (void)
  169. {
  170. int handle, flags, mode;
  171. char *arg;
  172. rpc_get (msock, RPC_STRING, &arg, RPC_INT, &flags, RPC_INT, &mode,
  173. RPC_END);
  174. handle = open (arg, flags, mode);
  175. send_status (handle, errno);
  176. g_free (arg);
  177. }
  178. static void
  179. do_read (void)
  180. {
  181. int handle, count, n;
  182. void *data;
  183. rpc_get (msock, RPC_INT, &handle, RPC_INT, &count, RPC_END);
  184. data = malloc (count);
  185. if (data == NULL) {
  186. send_status (-1, ENOMEM);
  187. return;
  188. }
  189. if (verbose)
  190. printf ("count=%d\n", count);
  191. n = read (handle, data, count);
  192. if (verbose)
  193. printf ("result=%d\n", n);
  194. if (n < 0)
  195. send_status (-1, errno);
  196. else {
  197. send_status (n, 0);
  198. rpc_send (msock, RPC_BLOCK, n, data, RPC_END);
  199. }
  200. g_free (data);
  201. }
  202. static void
  203. do_write (void)
  204. {
  205. int handle, count, status, written = 0;
  206. char buf[8192];
  207. rpc_get (msock, RPC_INT, &handle, RPC_INT, &count, RPC_END);
  208. status = 0;
  209. while (count) {
  210. int nbytes = count > 8192 ? 8192 : count;
  211. rpc_get (msock, RPC_BLOCK, nbytes, buf, RPC_END);
  212. status = write (handle, buf, nbytes);
  213. if (status < 0) {
  214. send_status (status, errno);
  215. return;
  216. }
  217. /* FIXED: amount written must be returned to caller */
  218. written += status;
  219. if (status < nbytes) {
  220. send_status (written, errno);
  221. return;
  222. }
  223. count -= nbytes;
  224. }
  225. send_status (written, errno);
  226. }
  227. static void
  228. do_lseek (void)
  229. {
  230. int handle, offset, whence, status;
  231. rpc_get (msock, RPC_INT, &handle, RPC_INT, &offset, RPC_INT, &whence,
  232. RPC_END);
  233. status = lseek (handle, offset, whence);
  234. send_status (status, errno);
  235. }
  236. static void
  237. do_close (void)
  238. {
  239. int handle, status;
  240. rpc_get (msock, RPC_INT, &handle, RPC_END);
  241. status = close (handle);
  242. send_status (status, errno);
  243. }
  244. /* }}} */
  245. /* {{{ Stat family routines */
  246. static void
  247. send_time (int sock, time_t t)
  248. {
  249. if (clnt_version == 1) {
  250. char *ct;
  251. int month;
  252. ct = ctime (&t);
  253. ct[3] = ct[10] = ct[13] = ct[16] = ct[19] = 0;
  254. /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
  255. if (ct[4] == 'J') {
  256. if (ct[5] == 'a') {
  257. month = 0;
  258. } else
  259. month = (ct[6] == 'n') ? 5 : 6;
  260. } else if (ct[4] == 'F') {
  261. month = 1;
  262. } else if (ct[4] == 'M') {
  263. month = (ct[6] == 'r') ? 2 : 5;
  264. } else if (ct[4] == 'A') {
  265. month = (ct[5] == 'p') ? 3 : 7;
  266. } else if (ct[4] == 'S') {
  267. month = 8;
  268. } else if (ct[4] == 'O') {
  269. month = 9;
  270. } else if (ct[4] == 'N') {
  271. month = 10;
  272. } else
  273. month = 11;
  274. rpc_send (sock, RPC_INT, atoi (&ct[17]), /* sec */
  275. RPC_INT, atoi (&ct[14]), /* min */
  276. RPC_INT, atoi (&ct[11]), /* hour */
  277. RPC_INT, atoi (&ct[8]), /* mday */
  278. RPC_INT, atoi (&ct[20]), /* year */
  279. RPC_INT, month, /* month */
  280. RPC_END);
  281. } else {
  282. long ltime = (long) t;
  283. char buf[BUF_SMALL];
  284. g_snprintf (buf, sizeof (buf), "%lx", ltime);
  285. rpc_send (sock, RPC_STRING, buf, RPC_END);
  286. }
  287. }
  288. static void
  289. send_stat_info (struct stat *st)
  290. {
  291. long mylong;
  292. int blocks =
  293. #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
  294. st->st_blocks;
  295. #else
  296. st->st_size / 1024;
  297. #endif
  298. #ifdef HAVE_STRUCT_STAT_ST_RDEV
  299. mylong = st->st_rdev;
  300. #else
  301. mylong = 0;
  302. #endif
  303. rpc_send (msock, RPC_INT, (long) mylong, RPC_INT, (long) st->st_ino,
  304. RPC_INT, (long) st->st_mode, RPC_INT, (long) st->st_nlink,
  305. RPC_INT, (long) st->st_uid, RPC_INT, (long) st->st_gid,
  306. RPC_INT, (long) st->st_size, RPC_INT, (long) blocks,
  307. RPC_END);
  308. send_time (msock, st->st_atime);
  309. send_time (msock, st->st_mtime);
  310. send_time (msock, st->st_ctime);
  311. }
  312. static void
  313. do_lstat (void)
  314. {
  315. struct stat st;
  316. char *file;
  317. int n;
  318. rpc_get (msock, RPC_STRING, &file, RPC_END);
  319. n = lstat (file, &st);
  320. send_status (n, errno);
  321. if (n >= 0)
  322. send_stat_info (&st);
  323. g_free (file);
  324. }
  325. static void
  326. do_fstat (void)
  327. {
  328. int handle;
  329. int n;
  330. struct stat st;
  331. rpc_get (msock, RPC_INT, &handle, RPC_END);
  332. n = fstat (handle, &st);
  333. send_status (n, errno);
  334. if (n < 0)
  335. return;
  336. send_stat_info (&st);
  337. }
  338. static void
  339. do_stat (void)
  340. {
  341. struct stat st;
  342. int n;
  343. char *file;
  344. rpc_get (msock, RPC_STRING, &file, RPC_END);
  345. n = stat (file, &st);
  346. send_status (n, errno);
  347. if (n >= 0)
  348. send_stat_info (&st);
  349. g_free (file);
  350. }
  351. /* }}} */
  352. /* {{{ Directory lookup operations */
  353. static struct {
  354. int used;
  355. DIR *dirs[OPENDIR_HANDLES];
  356. char *names[OPENDIR_HANDLES];
  357. } mcfs_DIR;
  358. static void
  359. close_handle (int handle)
  360. {
  361. if (mcfs_DIR.used > 0)
  362. mcfs_DIR.used--;
  363. if (mcfs_DIR.dirs[handle])
  364. closedir (mcfs_DIR.dirs[handle]);
  365. g_free (mcfs_DIR.names[handle]);
  366. mcfs_DIR.dirs[handle] = 0;
  367. mcfs_DIR.names[handle] = 0;
  368. }
  369. static void
  370. do_opendir (void)
  371. {
  372. int handle, i;
  373. char *arg;
  374. DIR *p;
  375. rpc_get (msock, RPC_STRING, &arg, RPC_END);
  376. if (mcfs_DIR.used == OPENDIR_HANDLES) {
  377. send_status (-1, ENFILE); /* Error */
  378. g_free (arg);
  379. return;
  380. }
  381. handle = -1;
  382. for (i = 0; i < OPENDIR_HANDLES; i++) {
  383. if (mcfs_DIR.dirs[i] == 0) {
  384. handle = i;
  385. break;
  386. }
  387. }
  388. if (handle == -1) {
  389. send_status (-1, EMFILE);
  390. g_free (arg);
  391. if (!inetd_started)
  392. fprintf (stderr,
  393. "OOPS! you have found a bug in mc - do_opendir()!\n");
  394. return;
  395. }
  396. if (verbose)
  397. printf ("handle=%d\n", handle);
  398. p = opendir (arg);
  399. if (p) {
  400. mcfs_DIR.dirs[handle] = p;
  401. mcfs_DIR.names[handle] = arg;
  402. mcfs_DIR.used++;
  403. /* Because 0 is an error value */
  404. rpc_send (msock, RPC_INT, handle + 1, RPC_INT, 0, RPC_END);
  405. } else {
  406. send_status (-1, errno);
  407. g_free (arg);
  408. }
  409. }
  410. /* Sends the complete directory listing, as well as the stat information */
  411. static void
  412. do_readdir (void)
  413. {
  414. struct dirent *dirent;
  415. struct stat st;
  416. int handle, n;
  417. rpc_get (msock, RPC_INT, &handle, RPC_END);
  418. if (!handle) {
  419. rpc_send (msock, RPC_INT, 0, RPC_END);
  420. return;
  421. }
  422. /* We incremented it in opendir */
  423. handle--;
  424. while ((dirent = readdir (mcfs_DIR.dirs[handle]))) {
  425. int fname_len;
  426. char *fname;
  427. int length = NLENGTH (dirent);
  428. rpc_send (msock, RPC_INT, length, RPC_END);
  429. rpc_send (msock, RPC_BLOCK, length, dirent->d_name, RPC_END);
  430. fname_len =
  431. strlen (mcfs_DIR.names[handle]) + strlen (dirent->d_name) + 2;
  432. fname = malloc (fname_len);
  433. g_snprintf (fname, fname_len, "%s/%s", mcfs_DIR.names[handle],
  434. dirent->d_name);
  435. n = lstat (fname, &st);
  436. g_free (fname);
  437. send_status (n, errno);
  438. if (n >= 0)
  439. send_stat_info (&st);
  440. }
  441. rpc_send (msock, RPC_INT, 0, RPC_END);
  442. }
  443. static void
  444. do_closedir (void)
  445. {
  446. int handle;
  447. rpc_get (msock, RPC_INT, &handle, RPC_END);
  448. close_handle (handle - 1);
  449. }
  450. /* }}} */
  451. /* {{{ Operations with one and two file name argument */
  452. static void
  453. do_chdir (void)
  454. {
  455. char *file;
  456. int status;
  457. rpc_get (msock, RPC_STRING, &file, RPC_END);
  458. status = chdir (file);
  459. send_status (status, errno);
  460. g_free (file);
  461. }
  462. static void
  463. do_rmdir (void)
  464. {
  465. char *file;
  466. int status;
  467. rpc_get (msock, RPC_STRING, &file, RPC_END);
  468. status = rmdir (file);
  469. send_status (status, errno);
  470. g_free (file);
  471. }
  472. static void
  473. do_mkdir (void)
  474. {
  475. char *file;
  476. int mode, status;
  477. rpc_get (msock, RPC_STRING, &file, RPC_INT, &mode, RPC_END);
  478. status = mkdir (file, mode);
  479. send_status (status, errno);
  480. g_free (file);
  481. }
  482. static void
  483. do_mknod (void)
  484. {
  485. char *file;
  486. int mode, dev, status;
  487. rpc_get (msock, RPC_STRING, &file, RPC_INT, &mode, RPC_INT, &dev,
  488. RPC_END);
  489. status = mknod (file, mode, dev);
  490. send_status (status, errno);
  491. g_free (file);
  492. }
  493. static void
  494. do_readlink (void)
  495. {
  496. char buf[2048];
  497. char *file;
  498. int n;
  499. rpc_get (msock, RPC_STRING, &file, RPC_END);
  500. n = readlink (file, buf, 2048 - 1);
  501. send_status (n, errno);
  502. if (n >= 0) {
  503. buf[n] = 0;
  504. rpc_send (msock, RPC_STRING, buf, RPC_END);
  505. }
  506. g_free (file);
  507. }
  508. static void
  509. do_unlink (void)
  510. {
  511. char *file;
  512. int status;
  513. rpc_get (msock, RPC_STRING, &file, RPC_END);
  514. status = unlink (file);
  515. send_status (status, errno);
  516. g_free (file);
  517. }
  518. static void
  519. do_rename (void)
  520. {
  521. char *f1, *f2;
  522. int status;
  523. rpc_get (msock, RPC_STRING, &f1, RPC_STRING, &f2, RPC_END);
  524. status = rename (f1, f2);
  525. send_status (status, errno);
  526. g_free (f1);
  527. g_free (f2);
  528. }
  529. static void
  530. do_symlink (void)
  531. {
  532. char *f1, *f2;
  533. int status;
  534. rpc_get (msock, RPC_STRING, &f1, RPC_STRING, &f2, RPC_END);
  535. status = symlink (f1, f2);
  536. send_status (status, errno);
  537. g_free (f1);
  538. g_free (f2);
  539. }
  540. static void
  541. do_link (void)
  542. {
  543. char *f1, *f2;
  544. int status;
  545. rpc_get (msock, RPC_STRING, &f1, RPC_STRING, &f2, RPC_END);
  546. status = link (f1, f2);
  547. send_status (status, errno);
  548. g_free (f1);
  549. g_free (f2);
  550. }
  551. /* }}} */
  552. /* {{{ Misc commands */
  553. static void
  554. do_gethome (void)
  555. {
  556. rpc_send (msock, RPC_STRING, (home_dir) ? home_dir : "/", RPC_END);
  557. }
  558. static void
  559. do_getupdir (void)
  560. {
  561. rpc_send (msock, RPC_STRING, (up_dir) ? up_dir : "/", RPC_END);
  562. }
  563. static void
  564. do_chmod (void)
  565. {
  566. char *file;
  567. int mode, status;
  568. rpc_get (msock, RPC_STRING, &file, RPC_INT, &mode, RPC_END);
  569. status = chmod (file, mode);
  570. send_status (status, errno);
  571. g_free (file);
  572. }
  573. static void
  574. do_chown (void)
  575. {
  576. char *file;
  577. int owner, group, status;
  578. rpc_get (msock, RPC_STRING, &file, RPC_INT, &owner, RPC_INT, &group,
  579. RPC_END);
  580. status = chown (file, owner, group);
  581. send_status (status, errno);
  582. g_free (file);
  583. }
  584. static void
  585. do_utime (void)
  586. {
  587. char *file;
  588. int status;
  589. long atime;
  590. long mtime;
  591. char *as;
  592. char *ms;
  593. struct utimbuf times;
  594. rpc_get (msock, RPC_STRING, &file, RPC_STRING, &as, RPC_STRING, &ms,
  595. RPC_END);
  596. sscanf (as, "%lx", &atime);
  597. sscanf (ms, "%lx", &mtime);
  598. if (verbose)
  599. printf ("Got a = %s, m = %s, comp a = %ld, m = %ld\n", as, ms,
  600. atime, mtime);
  601. g_free (as);
  602. g_free (ms);
  603. times.actime = (time_t) atime;
  604. times.modtime = (time_t) mtime;
  605. status = utime (file, &times);
  606. send_status (status, errno);
  607. g_free (file);
  608. }
  609. static void
  610. do_quit (void)
  611. {
  612. quit_server = 1;
  613. }
  614. #ifdef HAVE_PAM
  615. struct user_pass {
  616. const char *username;
  617. const char *password;
  618. };
  619. static int
  620. mc_pam_conversation (int messages, const struct pam_message **msg,
  621. struct pam_response **resp, void *appdata_ptr)
  622. {
  623. struct pam_response *r;
  624. struct user_pass *up = appdata_ptr;
  625. int status;
  626. r = (struct pam_response *) malloc (sizeof (struct pam_response) *
  627. messages);
  628. if (!r)
  629. return PAM_CONV_ERR;
  630. *resp = r;
  631. for (status = PAM_SUCCESS; messages--; msg++, r++) {
  632. switch ((*msg)->msg_style) {
  633. case PAM_PROMPT_ECHO_ON:
  634. r->resp = strdup (up->username);
  635. r->resp_retcode = PAM_SUCCESS;
  636. break;
  637. case PAM_PROMPT_ECHO_OFF:
  638. r->resp = strdup (up->password);
  639. r->resp_retcode = PAM_SUCCESS;
  640. break;
  641. case PAM_ERROR_MSG:
  642. r->resp = NULL;
  643. r->resp_retcode = PAM_SUCCESS;
  644. break;
  645. case PAM_TEXT_INFO:
  646. r->resp = NULL;
  647. r->resp_retcode = PAM_SUCCESS;
  648. break;
  649. }
  650. }
  651. return status;
  652. }
  653. static struct pam_conv conv = { &mc_pam_conversation, NULL };
  654. /* Return 0 if authentication failed, 1 otherwise */
  655. static int
  656. mc_pam_auth (const char *username, const char *password)
  657. {
  658. pam_handle_t *pamh;
  659. struct user_pass up;
  660. int status;
  661. up.username = username;
  662. up.password = password;
  663. conv.appdata_ptr = &up;
  664. status = pam_start ("mcserv", username, &conv, &pamh);
  665. if (status != PAM_SUCCESS)
  666. goto failed_pam;
  667. status = pam_authenticate (pamh, 0);
  668. if (status != PAM_SUCCESS)
  669. goto failed_pam;
  670. status = pam_acct_mgmt (pamh, 0);
  671. if (status != PAM_SUCCESS)
  672. goto failed_pam;
  673. status = pam_setcred (pamh, PAM_ESTABLISH_CRED);
  674. if (status != PAM_SUCCESS)
  675. goto failed_pam;
  676. pam_end (pamh, status);
  677. return 0;
  678. failed_pam:
  679. pam_end (pamh, status);
  680. return 1;
  681. }
  682. #else /* !HAVE_PAM */
  683. /* Keep reading until we find a \n */
  684. static int
  685. next_line (int sock)
  686. {
  687. char c;
  688. while (1) {
  689. if (read (sock, &c, 1) <= 0)
  690. return 0;
  691. if (c == '\n')
  692. return 1;
  693. }
  694. }
  695. static int
  696. ftp_answer (int sock, const char *text)
  697. {
  698. char answer[4];
  699. next_line (sock);
  700. socket_read_block (sock, answer, 3);
  701. answer[3] = 0;
  702. if (strcmp (answer, text) == 0)
  703. return 1;
  704. return 0;
  705. }
  706. static int
  707. send_string (int sock, const char *string)
  708. {
  709. return socket_write_block (sock, string, strlen (string));
  710. }
  711. static int
  712. do_ftp_auth (const char *username, const char *password)
  713. {
  714. struct sockaddr_in local_address;
  715. unsigned long inaddr;
  716. int my_socket;
  717. char answer[4];
  718. memset ((char *) &local_address, 0, sizeof (local_address));
  719. local_address.sin_family = AF_INET;
  720. /* FIXME: extract the ftp port with the proper function */
  721. local_address.sin_port = htons (21);
  722. /* Convert localhost to usable format */
  723. inaddr = inet_addr ("127.0.0.1");
  724. if (inaddr != INADDR_NONE)
  725. memcpy ((char *) &local_address.sin_addr, (char *) &inaddr,
  726. sizeof (inaddr));
  727. my_socket = socket (AF_INET, SOCK_STREAM, 0);
  728. if (my_socket < 0) {
  729. if (!isDaemon)
  730. fprintf (stderr, "do_auth: can't create socket\n");
  731. return 0;
  732. }
  733. if (connect
  734. (my_socket, (struct sockaddr *) &local_address,
  735. sizeof (local_address)) < 0) {
  736. fprintf (stderr,
  737. "do_auth: can't connect to ftp daemon for authentication\n");
  738. close (my_socket);
  739. return 0;
  740. }
  741. send_string (my_socket, "user ");
  742. send_string (my_socket, username);
  743. send_string (my_socket, "\r\n");
  744. if (!ftp_answer (my_socket, "331")) {
  745. send_string (my_socket, "quit\r\n");
  746. close (my_socket);
  747. return 0;
  748. }
  749. next_line (my_socket); /* Eat all the line */
  750. send_string (my_socket, "pass ");
  751. send_string (my_socket, password);
  752. send_string (my_socket, "\r\n");
  753. socket_read_block (my_socket, answer, 3);
  754. answer[3] = 0;
  755. send_string (my_socket, "\r\n");
  756. send_string (my_socket, "quit\r\n");
  757. close (my_socket);
  758. if (strcmp (answer, "230") == 0)
  759. return 1;
  760. return 0;
  761. }
  762. #ifdef HAVE_CRYPT
  763. static int
  764. do_classic_auth (const char *username, const char *password)
  765. {
  766. int ret = 0;
  767. const char *encr_pwd = NULL;
  768. struct passwd *pw;
  769. #ifdef HAVE_SHADOW
  770. struct spwd *spw;
  771. #endif
  772. pw = getpwnam (username);
  773. if (pw == NULL)
  774. return 0;
  775. #ifdef HAVE_SHADOW
  776. setspent ();
  777. /* Password expiration is not checked! */
  778. spw = getspnam (username);
  779. if (spw == NULL)
  780. encr_pwd = "*";
  781. else
  782. encr_pwd = spw->sp_pwdp;
  783. endspent ();
  784. #else
  785. encr_pwd = pw->pw_passwd;
  786. #endif
  787. if (strcmp (crypt (password, encr_pwd), encr_pwd) == 0)
  788. ret = 1;
  789. endpwent ();
  790. return ret;
  791. }
  792. #endif /* HAVE_CRYPT */
  793. #endif /* !HAVE_PAM */
  794. /* Try to authenticate the user based on:
  795. - PAM if the system has it, else it checks:
  796. - pwdauth if the system supports it.
  797. - conventional auth (check salt on /etc/passwd, crypt, and compare
  798. - try to contact the local ftp server and login (if -f flag used)
  799. */
  800. static int
  801. do_auth (const char *username, const char *password)
  802. {
  803. int auth = 0;
  804. struct passwd *this;
  805. if (strcmp (username, "anonymous") == 0)
  806. username = "ftp";
  807. #ifdef HAVE_PAM
  808. if (mc_pam_auth (username, password) == 0)
  809. auth = 1;
  810. #else /* if there is no pam */
  811. #ifdef HAVE_PWDAUTH
  812. if (pwdauth (username, password) == 0)
  813. auth = 1;
  814. else
  815. #endif
  816. #ifdef HAVE_CRYPT
  817. if (do_classic_auth (username, password))
  818. auth = 1;
  819. else
  820. #endif
  821. if (ftp)
  822. auth = do_ftp_auth (username, password);
  823. #endif /* not pam */
  824. if (!auth)
  825. return 0;
  826. this = getpwnam (username);
  827. if (this == 0)
  828. return 0;
  829. if (chdir (this->pw_dir) == -1)
  830. return 0;
  831. if (this->pw_dir[strlen (this->pw_dir) - 1] == '/')
  832. home_dir = strdup (this->pw_dir);
  833. else {
  834. char *new_home_dir = malloc (strlen (this->pw_dir) + 2);
  835. if (new_home_dir) {
  836. strcpy (new_home_dir, this->pw_dir);
  837. strcat (new_home_dir, "/");
  838. home_dir = new_home_dir;
  839. } else
  840. home_dir = "/";
  841. }
  842. if (setgid (this->pw_gid) == -1)
  843. return 0;
  844. #ifdef HAVE_INITGROUPS
  845. #ifdef NGROUPS_MAX
  846. if (NGROUPS_MAX > 1 && initgroups (this->pw_name, this->pw_gid))
  847. return 0;
  848. #endif
  849. #endif
  850. if (setuid (this->pw_uid))
  851. return 0;
  852. /* If the setuid call failed, then deny access */
  853. /* This should fix the problem on those machines with strange setups */
  854. if (getuid () != this->pw_uid)
  855. return 0;
  856. if ( (strcmp(username, "ftp") == 0) && (chroot(this->pw_dir) != 0) ) {
  857. error(0, errno, strerror(errno));
  858. return 0;
  859. }
  860. endpwent ();
  861. return auth;
  862. }
  863. #if 0
  864. static int
  865. do_rauth (int socket)
  866. {
  867. struct sockaddr_in from;
  868. struct hostent *hp;
  869. if (getpeername (0, (struct sockaddr *) &from, &fromlen) < 0)
  870. return 0;
  871. from.sin_port = ntohs ((unsigned short) from.sin_port);
  872. /* Strange, this should not happend */
  873. if (from.sin_family != AF_INET)
  874. return 0;
  875. hp = gethostbyaddr ((char *) &fromp.sin_addr, sizeof (struct in_addr),
  876. fromp.sin_family);
  877. }
  878. #endif
  879. static int
  880. do_rauth (int sock)
  881. {
  882. sock = 0; /* prevent warning */
  883. return 0;
  884. }
  885. static void
  886. login_reply (int _logged_in)
  887. {
  888. rpc_send (msock, RPC_INT, _logged_in ? MC_LOGINOK : MC_INVALID_PASS,
  889. RPC_END);
  890. }
  891. /* FIXME: Implement the anonymous login */
  892. static void
  893. do_login (void)
  894. {
  895. char *username;
  896. char *password;
  897. int result;
  898. rpc_get (msock, RPC_LIMITED_STRING, &up_dir, RPC_LIMITED_STRING,
  899. &username, RPC_END);
  900. if (verbose)
  901. printf ("username: %s\n", username);
  902. if (r_auth) {
  903. logged_in = do_rauth (msock);
  904. if (logged_in) {
  905. login_reply (logged_in);
  906. return;
  907. }
  908. }
  909. rpc_send (msock, RPC_INT, MC_NEED_PASSWORD, RPC_END);
  910. rpc_get (msock, RPC_INT, &result, RPC_END);
  911. if (result == MC_QUIT)
  912. DO_QUIT_VOID ();
  913. if (result != MC_PASS) {
  914. if (verbose)
  915. printf ("do_login: Unknown response: %d\n", result);
  916. DO_QUIT_VOID ();
  917. }
  918. rpc_get (msock, RPC_LIMITED_STRING, &password, RPC_END);
  919. logged_in = do_auth (username, password);
  920. endpwent ();
  921. login_reply (logged_in);
  922. }
  923. /* }}} */
  924. /* {{{ Server and dispatching functions */
  925. /* This structure must be kept in synch with mcfs.h enums */
  926. static const struct _command {
  927. const char *command;
  928. void (*callback) (void);
  929. } commands[] = {
  930. {
  931. "open", do_open}, {
  932. "close", do_close}, {
  933. "read", do_read}, {
  934. "write", do_write}, {
  935. "opendir", do_opendir}, {
  936. "readdir", do_readdir}, {
  937. "closedir", do_closedir}, {
  938. "stat ", do_stat}, {
  939. "lstat ", do_lstat}, {
  940. "fstat", do_fstat}, {
  941. "chmod", do_chmod}, {
  942. "chown", do_chown}, {
  943. "readlink ", do_readlink}, {
  944. "unlink", do_unlink}, {
  945. "rename", do_rename}, {
  946. "chdir ", do_chdir}, {
  947. "lseek", do_lseek}, {
  948. "rmdir", do_rmdir}, {
  949. "symlink", do_symlink}, {
  950. "mknod", do_mknod}, {
  951. "mkdir", do_mkdir}, {
  952. "link", do_link}, {
  953. "gethome", do_gethome}, {
  954. "getupdir", do_getupdir}, {
  955. "login", do_login}, {
  956. "quit", do_quit}, {
  957. "utime", do_utime}};
  958. static int ncommands = sizeof (commands) / sizeof (struct _command);
  959. static void
  960. exec_command (int command)
  961. {
  962. if (command < 0 || command >= ncommands
  963. || commands[command].command == 0) {
  964. fprintf (stderr, "Got unknown command: %d\n", command);
  965. DO_QUIT_VOID ();
  966. }
  967. if (verbose)
  968. printf ("Command: %s\n", commands[command].command);
  969. (*commands[command].callback) ();
  970. }
  971. static void
  972. check_version (void)
  973. {
  974. int version;
  975. rpc_get (msock, RPC_INT, &version, RPC_END);
  976. if (version >= 1 && version <= RPC_PROGVER)
  977. rpc_send (msock, RPC_INT, MC_VERSION_OK, RPC_END);
  978. else
  979. rpc_send (msock, RPC_INT, MC_VERSION_MISMATCH, RPC_END);
  980. clnt_version = version;
  981. }
  982. /* This routine is called by rpc_get/rpc_send when the connection is closed */
  983. void
  984. tcp_invalidate_socket (int sock)
  985. {
  986. if (verbose)
  987. printf ("Connection closed [socket %d]\n", sock);
  988. DO_QUIT_VOID ();
  989. }
  990. static void
  991. server (int sock)
  992. {
  993. int command;
  994. msock = sock;
  995. quit_server = 0;
  996. check_version ();
  997. do {
  998. if (rpc_get (sock, RPC_INT, &command, RPC_END)
  999. && (logged_in || command == MC_LOGIN))
  1000. exec_command (command);
  1001. } while (!quit_server);
  1002. }
  1003. /* }}} */
  1004. /* {{{ Net support code */
  1005. static const char *
  1006. get_client (int port)
  1007. {
  1008. int sock, newsocket;
  1009. unsigned int clilen;
  1010. struct sockaddr_in client_address, server_address;
  1011. int yes = 1;
  1012. sock = socket (AF_INET, SOCK_STREAM, 0);
  1013. if (sock < 0)
  1014. return "Cannot create socket";
  1015. /* Use this to debug: */
  1016. if (setsockopt
  1017. (sock, SOL_SOCKET, SO_REUSEADDR, (char *) &yes, sizeof (yes)) < 0)
  1018. return "setsockopt failed";
  1019. memset ((char *) &server_address, 0, sizeof (server_address));
  1020. server_address.sin_family = AF_INET;
  1021. server_address.sin_addr.s_addr = htonl (INADDR_ANY);
  1022. server_address.sin_port = htons (port);
  1023. if (bind
  1024. (sock, (struct sockaddr *) &server_address,
  1025. sizeof (server_address)) < 0)
  1026. return "Cannot bind";
  1027. listen (sock, 5);
  1028. for (;;) {
  1029. int child;
  1030. clilen = sizeof (client_address);
  1031. newsocket =
  1032. accept (sock, (struct sockaddr *) &client_address, &clilen);
  1033. child = fork ();
  1034. if (isDaemon != 0 && child != 0) {
  1035. int status;
  1036. close (newsocket);
  1037. waitpid (child, &status, 0);
  1038. continue;
  1039. }
  1040. if (isDaemon && fork ())
  1041. exit (0);
  1042. server (newsocket);
  1043. close (newsocket);
  1044. return 0;
  1045. }
  1046. }
  1047. #ifdef HAVE_PMAP_SET
  1048. static void
  1049. signal_int_handler (int sig)
  1050. {
  1051. (void) sig;
  1052. pmap_unset (RPC_PROGNUM, RPC_PROGVER);
  1053. }
  1054. #endif
  1055. #ifndef IPPORT_RESERVED
  1056. #define IPPORT_RESERVED 1024
  1057. #endif
  1058. static int
  1059. get_port_number (void)
  1060. {
  1061. int port = 0;
  1062. #ifdef HAVE_RRESVPORT
  1063. int start_port = IPPORT_RESERVED;
  1064. port = rresvport (&start_port);
  1065. if (port == -1) {
  1066. if (geteuid () == 0) {
  1067. fprintf (stderr,
  1068. "Cannot bind the server on a reserved port\n");
  1069. DO_QUIT_NONVOID (-1);
  1070. }
  1071. port = 0;
  1072. }
  1073. #endif
  1074. if (port)
  1075. return port;
  1076. port = mcserver_port;
  1077. return port;
  1078. }
  1079. static void
  1080. register_port (int port, int abort_if_fail)
  1081. {
  1082. #ifdef HAVE_PMAP_SET
  1083. /* Register our service with the portmapper */
  1084. /* protocol: pmap_set (prognum, versnum, protocol, portp) */
  1085. if (pmap_set (RPC_PROGNUM, RPC_PROGVER, IPPROTO_TCP, port))
  1086. signal (SIGINT, signal_int_handler);
  1087. else {
  1088. fprintf (stderr, "Cannot register service with portmapper\n");
  1089. if (abort_if_fail)
  1090. exit (EXIT_FAILURE);
  1091. }
  1092. #else
  1093. (void) port;
  1094. if (abort_if_fail) {
  1095. fprintf (stderr,
  1096. "This system lacks port registration, try using the -p\n"
  1097. "flag to force installation at a given port");
  1098. }
  1099. #endif
  1100. }
  1101. /* }}} */
  1102. int
  1103. main (int argc, char *argv[])
  1104. {
  1105. const char *result;
  1106. int c;
  1107. while ((c = getopt (argc, argv, "fdiqp:v")) != -1) {
  1108. switch (c) {
  1109. case 'd':
  1110. isDaemon = 1;
  1111. verbose = 0;
  1112. break;
  1113. case 'v':
  1114. verbose = 1;
  1115. break;
  1116. case 'f':
  1117. ftp = 1;
  1118. break;
  1119. case 'q':
  1120. verbose = 0;
  1121. break;
  1122. case 'p':
  1123. portnum = atoi (optarg);
  1124. break;
  1125. case 'i':
  1126. inetd_started = 1;
  1127. break;
  1128. case 'r':
  1129. r_auth = 1;
  1130. break;
  1131. default:
  1132. fprintf (stderr,
  1133. "Usage is: mcserv [options] [-p portnum]\n\n"
  1134. "options are:\n" "-d become a daemon (sets -q)\n"
  1135. "-q quiet mode\n"
  1136. /* "-r use rhost based authentication\n" */
  1137. #ifndef HAVE_PAM
  1138. "-f force ftp authentication\n"
  1139. #endif
  1140. "-v verbose mode\n"
  1141. "-p to specify a port number to listen\n");
  1142. exit (0);
  1143. }
  1144. }
  1145. if (isDaemon && fork ())
  1146. exit (0);
  1147. if (portnum == 0)
  1148. portnum = get_port_number ();
  1149. if (portnum != -1) {
  1150. register_port (portnum, 0);
  1151. if (verbose)
  1152. printf ("Using port %d\n", portnum);
  1153. result = get_client (portnum);
  1154. if (result != NULL)
  1155. perror (result);
  1156. #ifdef HAVE_PMAP_SET
  1157. if (isDaemon == 0)
  1158. pmap_unset (RPC_PROGNUM, RPC_PROGVER);
  1159. #endif
  1160. }
  1161. exit (return_code);
  1162. }
  1163. /* FIXME: This function should not be used in mcserv */
  1164. void
  1165. vfs_die (const char *m)
  1166. {
  1167. fputs (m, stderr);
  1168. exit (EXIT_FAILURE);
  1169. }