mcserv.c 27 KB

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