mcserv.c 28 KB

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