mcserv.c 27 KB

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