*** empty log message ***
[midnight-commander.git] / vfs / mcserv.c
blob5e8ee9bf6ffb713bf216be92d9b49612f76d15e8
1 /* Server for the Midnight Commander Virtual File System.
3 Copyright (C) 1995, 1996, 1997 The Free Software Foundation
5 Written by:
6 Miguel de Icaza, 1995, 1997,
7 Andrej Borsenkow 1996.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 TODO:
24 opendir instead of keeping its table of file handles could return
25 the pointer and expect the client to send a proper value back each
26 time :-)
28 We should use syslog to register login/logout.
32 /* {{{ Includes and global variables */
34 #include <config.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #ifdef HAVE_UNISTD_H
38 # include <unistd.h>
39 #endif
40 #include <fcntl.h>
41 #include <string.h>
42 #ifdef HAVE_LIMITS_H
43 # include <limits.h>
44 #endif
45 #ifndef NGROUPS_MAX
46 # include <sys/param.h>
47 # ifdef NGROUPS
48 # define NGROUPS_MAX NGROUPS
49 # endif
50 #endif
51 #ifdef HAVE_GRP_H
52 # include <grp.h>
53 #endif
54 #ifdef HAVE_CRYPT_H
55 # include <crypt.h>
56 #endif
57 #include <sys/types.h>
58 #include <sys/stat.h>
59 #include <sys/wait.h>
60 #include <errno.h>
61 #include <signal.h>
63 /* Network include files */
64 #include <sys/socket.h>
65 #include <netinet/in.h>
66 #include <netdb.h>
67 #ifdef HAVE_ARPA_INET_H
68 #include <arpa/inet.h>
69 #endif
70 #ifdef HAVE_PMAP_SET
71 # include <rpc/rpc.h>
72 # include <rpc/pmap_prot.h>
73 # ifdef HAVE_RPC_PMAP_CLNT_H
74 # include <rpc/pmap_clnt.h>
75 # endif
76 #endif
78 /* Authentication include files */
79 #include <pwd.h>
80 #ifdef HAVE_PAM
81 # include <security/pam_misc.h>
82 # ifndef PAM_ESTABLISH_CRED
83 # define PAM_ESTABLISH_CRED PAM_CRED_ESTABLISH
84 # endif
85 #endif
87 #include "utilvfs.h"
89 #include "vfs.h"
90 #include "mcfs.h"
91 #include "tcputil.h"
93 /* The socket from which we accept commands */
94 int msock;
96 /* Requested version number from client */
97 static int clnt_version;
99 /* If non zero, we accept further commands */
100 int logged_in = 0;
102 /* Home directory */
103 char *home_dir = NULL;
105 char *up_dir = NULL;
107 /* Were we started from inetd? */
108 int inetd_started = 0;
110 /* Are we running as a daemon? */
111 int isDaemon = 0;
113 /* guess */
114 int verbose = 0;
116 /* ftp auth */
117 int ftp = 0;
119 /* port number in which we listen to connections,
120 * if zero, we try to contact the portmapper to get a port, and
121 * if it's not possible, then we use a hardcoded value
123 int portnum = 0;
125 /* if the server will use rcmd based authentication (hosts.equiv .rhosts) */
126 int r_auth = 0;
128 #define OPENDIR_HANDLES 8
130 #define DO_QUIT_VOID() \
131 do { \
132 quit_server = 1; \
133 return_code = 1; \
134 return; \
135 } while (0)
137 /* Only used by get_port_number */
138 #define DO_QUIT_NONVOID(a) \
139 do { \
140 quit_server = 1; \
141 return_code = 1; \
142 return (a); \
143 } while (0)
145 char buffer [4096];
146 int debug = 1;
147 static int quit_server;
148 static int return_code;
150 /* }}} */
152 /* {{{ Misc routines */
154 static void send_status (int status, int errno_number)
156 rpc_send (msock, RPC_INT, status, RPC_INT, errno_number, RPC_END);
157 errno = 0;
160 /* }}} */
162 /* {{{ File with handle operations */
164 static void do_open (void)
166 int handle, flags, mode;
167 char *arg;
169 rpc_get (msock, RPC_STRING, &arg, RPC_INT, &flags, RPC_INT, &mode,RPC_END);
171 handle = open (arg, flags, mode);
172 send_status (handle, errno);
173 g_free (arg);
176 static void do_read (void)
178 int handle, count, n;
179 void *data;
181 rpc_get (msock, RPC_INT, &handle, RPC_INT, &count, RPC_END);
182 data = g_malloc (count);
183 if (!data){
184 send_status (-1, ENOMEM);
185 return;
187 if (verbose) printf ("count=%d\n", count);
188 n = read (handle, data, count);
189 if (verbose) printf ("result=%d\n", n);
190 if (n < 0){
191 send_status (-1, errno);
192 return;
194 send_status (n, 0);
195 rpc_send (msock, RPC_BLOCK, n, data, RPC_END);
197 g_free (data);
200 static void do_write (void)
202 int handle, count, status, written = 0;
203 char buf[8192];
205 rpc_get (msock, RPC_INT, &handle, RPC_INT, &count, RPC_END);
206 status = 0;
207 while (count) {
208 int nbytes = count > 8192 ? 8192 : count;
210 rpc_get (msock, RPC_BLOCK, nbytes, buf, RPC_END);
211 status = write (handle, buf, nbytes);
212 if (status < 0) {
213 send_status (status, errno);
214 return;
216 /* FIXED: amount written must be returned to caller */
217 written += status;
218 if (status < nbytes) {
219 send_status (written, errno);
220 return;
222 count -= nbytes;
224 send_status (written, errno);
227 static void do_lseek (void)
229 int handle, offset, whence, status;
231 rpc_get (msock,
232 RPC_INT, &handle,
233 RPC_INT, &offset,
234 RPC_INT, &whence, RPC_END);
235 status = lseek (handle, offset, whence);
236 send_status (status, errno);
239 static void do_close (void)
241 int handle, status;
243 rpc_get (msock, RPC_INT, &handle, RPC_END);
244 status = close (handle);
245 send_status (status, errno);
248 /* }}} */
250 /* {{{ Stat family routines */
252 static void send_time (int sock, time_t time)
254 if (clnt_version == 1) {
255 char *ct;
256 int month;
258 ct = ctime (&time);
259 ct [3] = ct [10] = ct [13] = ct [16] = ct [19] = 0;
261 /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
262 if (ct [4] == 'J'){
263 if (ct [5] == 'a'){
264 month = 0;
265 } else
266 month = (ct [6] == 'n') ? 5 : 6;
267 } else if (ct [4] == 'F'){
268 month = 1;
269 } else if (ct [4] == 'M'){
270 month = (ct [6] == 'r') ? 2 : 5;
271 } else if (ct [4] == 'A'){
272 month = (ct [5] == 'p') ? 3 : 7;
273 } else if (ct [4] == 'S'){
274 month = 8;
275 } else if (ct [4] == 'O'){
276 month = 9;
277 } else if (ct [4] == 'N'){
278 month = 10;
279 } else
280 month = 11;
281 rpc_send (msock,
282 RPC_INT, atoi (&ct [17]), /* sec */
283 RPC_INT, atoi (&ct [14]), /* min */
284 RPC_INT, atoi (&ct [11]), /* hour */
285 RPC_INT, atoi (&ct [8]), /* mday */
286 RPC_INT, atoi (&ct [20]), /* year */
287 RPC_INT, month, /* month */
288 RPC_END);
289 } else {
290 long ltime = (long) time;
291 char buf[BUF_SMALL];
293 g_snprintf (buf, sizeof(buf), "%lx", ltime);
294 rpc_send (msock,
295 RPC_STRING, buf,
296 RPC_END);
300 static void send_stat_info (struct stat *st)
302 long mylong;
303 int blocks =
304 #ifdef HAVE_ST_BLOCKS
305 st->st_blocks;
306 #else
307 st->st_size / 1024;
308 #endif
310 #ifdef HAVE_ST_RDEV
311 mylong = st->st_rdev;
312 #else
313 mylong = 0;
314 #endif
315 rpc_send (msock, RPC_INT, (long) mylong,
316 RPC_INT, (long) st->st_ino,
317 RPC_INT, (long) st->st_mode,
318 RPC_INT, (long) st->st_nlink,
319 RPC_INT, (long) st->st_uid,
320 RPC_INT, (long) st->st_gid,
321 RPC_INT, (long) st->st_size,
322 RPC_INT, (long) blocks, RPC_END);
323 send_time (msock, st->st_atime);
324 send_time (msock, st->st_mtime);
325 send_time (msock, st->st_ctime);
328 static void do_lstat (void)
330 struct stat st;
331 char *file;
332 int n;
334 rpc_get (msock, RPC_STRING, &file, RPC_END);
335 n = lstat (file, &st);
336 send_status (n, errno);
337 if (n >= 0)
338 send_stat_info (&st);
339 g_free (file);
342 static void do_fstat (void)
344 int handle;
345 int n;
346 struct stat st;
348 rpc_get (msock, RPC_INT, &handle, RPC_END);
349 n = fstat (handle, &st);
350 send_status (n, errno);
351 if (n < 0)
352 return;
354 send_stat_info (&st);
357 static void do_stat (void)
359 struct stat st;
360 int n;
361 char *file;
363 rpc_get (msock, RPC_STRING, &file, RPC_END);
365 n = stat (file, &st);
366 send_status (n, errno);
367 if (n >= 0)
368 send_stat_info (&st);
369 g_free (file);
372 /* }}} */
374 /* {{{ Directory lookup operations */
376 static struct {
377 int used;
378 DIR *dirs [OPENDIR_HANDLES];
379 char *names [OPENDIR_HANDLES];
380 } mcfs_DIR;
382 static void close_handle (int handle)
384 if (mcfs_DIR.used > 0) mcfs_DIR.used--;
385 if (mcfs_DIR.dirs [handle])
386 closedir (mcfs_DIR.dirs [handle]);
387 if (mcfs_DIR.names [handle])
388 g_free (mcfs_DIR.names [handle]);
389 mcfs_DIR.dirs [handle] = 0;
390 mcfs_DIR.names [handle] = 0;
393 static void do_opendir (void)
395 int handle, i;
396 char *arg;
397 DIR *p;
399 rpc_get (msock, RPC_STRING, &arg, RPC_END);
401 if (mcfs_DIR.used == OPENDIR_HANDLES){
402 send_status (-1, ENFILE); /* Error */
403 g_free (arg);
404 return;
407 handle = -1;
408 for (i = 0; i < OPENDIR_HANDLES; i++){
409 if (mcfs_DIR.dirs [i] == 0){
410 handle = i;
411 break;
415 if (handle == -1){
416 send_status (-1, EMFILE);
417 g_free (arg);
418 if (!inetd_started)
419 fprintf (stderr, "OOPS! you have found a bug in mc - do_opendir()!\n");
420 return;
423 if (verbose) printf ("handle=%d\n", handle);
424 p = opendir (arg);
425 if (p){
426 mcfs_DIR.dirs [handle] = p;
427 mcfs_DIR.names [handle] = arg;
428 mcfs_DIR.used ++;
430 /* Because 0 is an error value */
431 rpc_send (msock, RPC_INT, handle+1, RPC_INT, 0, RPC_END);
433 } else {
434 send_status (-1, errno);
435 g_free (arg);
439 /* Sends the complete directory listing, as well as the stat information */
440 static void do_readdir (void)
442 struct dirent *dirent;
443 struct stat st;
444 int handle, n;
445 char *fname = 0;
447 rpc_get (msock, RPC_INT, &handle, RPC_END);
449 if (!handle){
450 rpc_send (msock, RPC_INT, 0, RPC_END);
451 return;
454 /* We incremented it in opendir */
455 handle --;
457 while ((dirent = readdir (mcfs_DIR.dirs [handle]))){
458 int length = NLENGTH (dirent);
460 rpc_send (msock, RPC_INT, length, RPC_END);
461 rpc_send (msock, RPC_BLOCK, length, dirent->d_name, RPC_END);
462 fname = g_strconcat (mcfs_DIR.names [handle],
463 PATH_SEP_STR, dirent->d_name, NULL);
464 n = lstat (fname, &st);
465 send_status (n, errno);
466 g_free (fname);
467 if (n >= 0)
468 send_stat_info (&st);
470 rpc_send (msock, RPC_INT, 0, RPC_END);
473 static void do_closedir (void)
475 int handle;
477 rpc_get (msock, RPC_INT, &handle, RPC_END);
478 close_handle (handle-1);
481 /* }}} */
483 /* {{{ Operations with one and two file name argument */
485 static void do_chdir (void)
487 char *file;
488 int status;
490 rpc_get (msock, RPC_STRING, &file, RPC_END);
492 status = chdir (file);
493 send_status (status, errno);
494 g_free (file);
497 static void do_rmdir (void)
499 char *file;
500 int status;
502 rpc_get (msock, RPC_STRING, &file, RPC_END);
504 status = rmdir (file);
505 send_status (status, errno);
506 g_free (file);
509 static void do_mkdir (void)
511 char *file;
512 int mode, status;
514 rpc_get (msock, RPC_STRING, &file, RPC_INT, &mode, RPC_END);
516 status = mkdir (file, mode);
517 send_status (status, errno);
518 g_free (file);
521 static void do_mknod (void)
523 char *file;
524 int mode, dev, status;
526 rpc_get (msock, RPC_STRING, &file, RPC_INT, &mode, RPC_INT, &dev, RPC_END);
528 status = mknod (file, mode, dev);
529 send_status (status, errno);
530 g_free (file);
533 static void do_readlink (void)
535 char buffer [2048];
536 char *file;
537 int n;
539 rpc_get (msock, RPC_STRING, &file, RPC_END);
540 n = readlink (file, buffer, 2048);
541 send_status (n, errno);
542 if (n >= 0) {
543 buffer [n] = 0;
544 rpc_send (msock, RPC_STRING, buffer, RPC_END);
546 g_free (file);
549 static void do_unlink (void)
551 char *file;
552 int status;
554 rpc_get (msock, RPC_STRING, &file, RPC_END);
555 status = unlink (file);
556 send_status (status, errno);
557 g_free (file);
560 static void do_rename (void)
562 char *f1, *f2;
563 int status;
565 rpc_get (msock, RPC_STRING, &f1, RPC_STRING, &f2, RPC_END);
566 status = rename (f1, f2);
567 send_status (status, errno);
568 g_free (f1); g_free (f2);
571 static void do_symlink (void)
573 char *f1, *f2;
574 int status;
576 rpc_get (msock, RPC_STRING, &f1, RPC_STRING, &f2, RPC_END);
577 status = symlink (f1, f2);
578 send_status (status, errno);
579 g_free (f1); g_free (f2);
582 static void do_link (void)
584 char *f1, *f2;
585 int status;
587 rpc_get (msock, RPC_STRING, &f1, RPC_STRING, &f2, RPC_END);
588 status = link (f1, f2);
589 send_status (status, errno);
590 g_free (f1); g_free (f2);
594 /* }}} */
596 /* {{{ Misc commands */
598 static void do_gethome (void)
600 rpc_send (msock, RPC_STRING, (home_dir) ? home_dir : "/", RPC_END);
603 static void do_getupdir (void)
605 rpc_send (msock, RPC_STRING, (up_dir) ? up_dir : "/", RPC_END);
608 static void do_chmod (void)
610 char *file;
611 int mode, status;
613 rpc_get (msock, RPC_STRING, &file, RPC_INT, &mode, RPC_END);
614 status = chmod (file, mode);
615 send_status (status, errno);
616 g_free (file);
619 static void do_chown (void)
621 char *file;
622 int owner, group, status;
624 rpc_get (msock, RPC_STRING, &file,RPC_INT, &owner, RPC_INT,&group,RPC_END);
625 status = chown (file, owner, group);
626 send_status (status, errno);
627 g_free (file);
630 static void do_utime (void)
632 char *file;
633 int status;
634 long atime;
635 long mtime;
636 char *as;
637 char *ms;
638 struct utimbuf times;
640 rpc_get (msock, RPC_STRING, &file,
641 RPC_STRING, &as,
642 RPC_STRING, &ms,
643 RPC_END);
644 sscanf (as, "%lx", &atime);
645 sscanf (ms, "%lx", &mtime);
646 if (verbose) printf ("Got a = %s, m = %s, comp a = %ld, m = %ld\n",
647 as, ms, atime, mtime);
648 g_free (as);
649 g_free (ms);
650 times.actime = (time_t) atime;
651 times.modtime = (time_t) mtime;
652 status = utime (file, &times);
653 send_status (status, errno);
654 g_free (file);
657 static void do_quit (void)
659 quit_server = 1;
662 #ifdef HAVE_PAM
664 struct user_pass {
665 char *username;
666 char *password;
669 static int
670 mc_pam_conversation (int messages, const struct pam_message **msg,
671 struct pam_response **resp, void *appdata_ptr)
673 struct pam_response *r;
674 struct user_pass *up = appdata_ptr;
675 int status;
677 r = g_new (struct pam_response, messages);
678 if (!r)
679 return PAM_CONV_ERR;
680 *resp = r;
682 for (status = PAM_SUCCESS; messages--; msg++, r++){
683 switch ((*msg)->msg_style){
685 case PAM_PROMPT_ECHO_ON:
686 r->resp = g_strdup (up->username);
687 r->resp_retcode = PAM_SUCCESS;
688 break;
690 case PAM_PROMPT_ECHO_OFF:
691 r->resp = g_strdup (up->password);
692 r->resp_retcode = PAM_SUCCESS;
693 break;
695 case PAM_ERROR_MSG:
696 r->resp = NULL;
697 r->resp_retcode = PAM_SUCCESS;
698 break;
700 case PAM_TEXT_INFO:
701 r->resp = NULL;
702 r->resp_retcode = PAM_SUCCESS;
703 break;
706 return status;
709 static struct pam_conv conv = { &mc_pam_conversation, NULL };
712 /* Return 0 if authentication failed, 1 otherwise */
713 static int
714 mc_pam_auth (char *username, char *password)
716 pam_handle_t *pamh;
717 struct user_pass up;
718 int status;
720 up.username = username;
721 up.password = password;
722 conv.appdata_ptr = &up;
724 if ((status = pam_start("mcserv", username, &conv, &pamh)) != PAM_SUCCESS)
725 goto failed_pam;
726 if ((status = pam_authenticate (pamh, 0)) != PAM_SUCCESS)
727 goto failed_pam;
728 if ((status = pam_acct_mgmt (pamh, 0)) != PAM_SUCCESS)
729 goto failed_pam;
730 if ((status = pam_setcred (pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS)
731 goto failed_pam;
732 pam_end (pamh, status);
733 return 0;
735 failed_pam:
736 pam_end (pamh, status);
737 return 1;
740 #else /* Code for non-PAM authentication */
742 /* Keep reading until we find a \n */
743 static int next_line (int socket)
745 char c;
747 while (1){
748 if (read (socket, &c, 1) <= 0)
749 return 0;
750 if (c == '\n')
751 return 1;
755 static int ftp_answer (int sock, char *text)
757 char answer [4];
759 next_line (sock);
760 socket_read_block (sock, answer, 3);
761 answer [3] = 0;
762 if (strcmp (answer, text) == 0)
763 return 1;
764 return 0;
767 static int do_ftp_auth (char *username, char *password)
769 struct sockaddr_in local_address;
770 unsigned long inaddr;
771 int my_socket;
772 char answer [4];
774 memset ((char *) &local_address, 0, sizeof (local_address));
776 local_address.sin_family = AF_INET;
777 /* FIXME: extract the ftp port with the proper function */
778 local_address.sin_port = htons (21);
780 /* Convert localhost to usable format */
781 if ((inaddr = inet_addr ("127.0.0.1")) != -1)
782 memcpy ((char *) &local_address.sin_addr, (char *) &inaddr,
783 sizeof (inaddr));
785 if ((my_socket = socket (AF_INET, SOCK_STREAM, 0)) < 0){
786 if (!isDaemon) fprintf (stderr, "do_auth: can't create socket\n");
787 return 0;
789 if (connect (my_socket, (struct sockaddr *) &local_address,
790 sizeof (local_address)) < 0){
791 fprintf (stderr,
792 "do_auth: can't connect to ftp daemon for authentication\n");
793 close (my_socket);
794 return 0;
796 send_string (my_socket, "user ");
797 send_string (my_socket, username);
798 send_string (my_socket, "\r\n");
799 if (!ftp_answer (my_socket, "331")){
800 send_string (my_socket, "quit\r\n");
801 close (my_socket);
802 return 0;
804 next_line (my_socket); /* Eat all the line */
805 send_string (my_socket, "pass ");
806 send_string (my_socket, password);
807 send_string (my_socket, "\r\n");
808 socket_read_block (my_socket, answer, 3);
809 answer [3] = 0;
810 send_string (my_socket, "\r\n");
811 send_string (my_socket, "quit\r\n");
812 close (my_socket);
813 if (strcmp (answer, "230") == 0)
814 return 1;
815 return 0;
818 #ifdef NEED_CRYPT_PROTOTYPE
819 extern char *crypt (const char *, const char *);
820 #endif
822 static int do_classic_auth (char *username, char *password)
824 struct passwd *this;
825 int ret;
827 if ((this = getpwnam (username)) == 0)
828 return 0;
830 #ifdef HAVE_CRYPT
831 if (strcmp (crypt (password, this->pw_passwd), this->pw_passwd) == 0){
832 ret = 1;
833 } else
834 #endif
836 ret = 0;
838 endpwent ();
839 return ret;
841 #endif /* non-PAM authentication */
843 /* Try to authenticate the user based on:
844 - PAM if the system has it, else it checks:
845 - pwdauth if the system supports it.
846 - conventional auth (check salt on /etc/passwd, crypt, and compare
847 - try to contact the local ftp server and login (if -f flag used)
849 static int
850 do_auth (char *username, char *password)
852 int auth = 0;
853 struct passwd *this;
855 if (strcmp (username, "anonymous") == 0)
856 username = "ftp";
858 #ifdef HAVE_PAM
859 if (mc_pam_auth (username, password) == 0)
860 auth = 1;
861 #else /* if there is no pam */
862 #ifdef HAVE_PWDAUTH
863 if (pwdauth (username, password) == 0)
864 auth = 1;
865 else
866 #endif
867 if (do_classic_auth (username, password))
868 auth = 1;
869 else if (ftp)
870 auth = do_ftp_auth (username, password);
871 #endif /* not pam */
873 if (!auth)
874 return 0;
876 this = getpwnam (username);
877 if (this == 0)
878 return 0;
880 if (chdir (this->pw_dir) == -1)
881 return 0;
883 if (this->pw_dir [strlen (this->pw_dir) - 1] == '/')
884 home_dir = g_strdup (this->pw_dir);
885 else {
886 home_dir = g_malloc (strlen (this->pw_dir) + 2);
887 if (home_dir) {
888 strcpy (home_dir, this->pw_dir);
889 strcat (home_dir, "/");
890 } else
891 home_dir = "/";
895 if (setgid (this->pw_gid) == -1)
896 return 0;
898 #ifdef HAVE_INITGROUPS
899 #ifdef NGROUPS_MAX
900 if (NGROUPS_MAX > 1 && initgroups (this->pw_name, this->pw_gid))
901 return 0;
902 #endif
903 #endif
905 #if defined (HAVE_SETUID)
906 if (setuid (this->pw_uid))
907 return 0;
908 #elif defined (HAVE_SETREUID)
909 if (setreuid (this->pw_uid, this->pw_uid))
910 return 0;
911 #endif
913 /* If the setuid call failed, then deny access */
914 /* This should fix the problem on those machines with strange setups */
915 if (getuid () != this->pw_uid)
916 return 0;
918 if (strcmp (username, "ftp") == 0)
919 chroot (this->pw_dir);
921 endpwent ();
922 return auth;
925 #if 0
926 static int do_rauth (int socket)
928 struct sockaddr_in from;
929 struct hostent *hp;
931 if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0)
932 return 0;
933 from.sin_port = ntohs ((unsigned short) from.sin_port);
935 /* Strange, this should not happend */
936 if (from.sin_family != AF_INET)
937 return 0;
939 hp = gethostbyaddr((char *)&fromp.sin_addr, sizeof (struct in_addr),
940 fromp.sin_family);
943 #endif
945 static int do_rauth (int msock)
947 return 0;
950 static void login_reply (int logged_in)
952 rpc_send (msock, RPC_INT,
953 logged_in ? MC_LOGINOK : MC_INVALID_PASS,
954 RPC_END);
957 /* FIXME: Implement the anonymous login */
958 static void do_login (void)
960 char *username;
961 char *password;
962 int result;
964 rpc_get (msock, RPC_LIMITED_STRING, &up_dir, RPC_LIMITED_STRING, &username, RPC_END);
965 if (verbose) printf ("username: %s\n", username);
967 if (r_auth){
968 logged_in = do_rauth (msock);
969 if (logged_in){
970 login_reply (logged_in);
971 return;
974 rpc_send (msock, RPC_INT, MC_NEED_PASSWORD, RPC_END);
975 rpc_get (msock, RPC_INT, &result, RPC_END);
976 if (result == MC_QUIT)
977 DO_QUIT_VOID ();
978 if (result != MC_PASS){
979 if (verbose) printf ("do_login: Unknown response: %d\n", result);
980 DO_QUIT_VOID ();
982 rpc_get (msock, RPC_LIMITED_STRING, &password, RPC_END);
983 logged_in = do_auth (username, password);
984 endpwent ();
985 login_reply (logged_in);
988 /* }}} */
990 /* {{{ Server and dispatching functions */
992 /* This structure must be kept in synch with mcfs.h enums */
994 static struct _command {
995 char *command;
996 void (*callback)(void);
997 } commands [] = {
998 { "open", do_open },
999 { "close", do_close },
1000 { "read", do_read },
1001 { "write", do_write },
1002 { "opendir", do_opendir },
1003 { "readdir", do_readdir },
1004 { "closedir", do_closedir },
1005 { "stat ", do_stat },
1006 { "lstat ", do_lstat },
1007 { "fstat", do_fstat },
1008 { "chmod", do_chmod },
1009 { "chown", do_chown },
1010 { "readlink ", do_readlink },
1011 { "unlink", do_unlink },
1012 { "rename", do_rename },
1013 { "chdir ", do_chdir },
1014 { "lseek", do_lseek },
1015 { "rmdir", do_rmdir },
1016 { "symlink", do_symlink },
1017 { "mknod", do_mknod },
1018 { "mkdir", do_mkdir },
1019 { "link", do_link },
1020 { "gethome", do_gethome },
1021 { "getupdir", do_getupdir },
1022 { "login", do_login },
1023 { "quit", do_quit },
1024 { "utime", do_utime },
1027 static int ncommands = sizeof(commands)/sizeof(struct _command);
1029 static void exec_command (int command)
1031 if (command < 0 ||
1032 command >= ncommands ||
1033 commands [command].command == 0){
1034 fprintf (stderr, "Got unknown command: %d\n", command);
1035 DO_QUIT_VOID ();
1037 if (verbose) printf ("Command: %s\n", commands [command].command);
1038 (*commands [command].callback)();
1041 static void check_version (void)
1043 int version;
1045 rpc_get (msock, RPC_INT, &version, RPC_END);
1046 if (version >= 1 &&
1047 version <= RPC_PROGVER)
1048 rpc_send (msock, RPC_INT, MC_VERSION_OK, RPC_END);
1049 else
1050 rpc_send (msock, RPC_INT, MC_VERSION_MISMATCH, RPC_END);
1052 clnt_version = version;
1055 /* This routine is called by rpc_get/rpc_send when the connection is closed */
1056 void tcp_invalidate_socket (int sock)
1058 if (verbose) printf ("Connection closed\n");
1059 DO_QUIT_VOID();
1062 static void server (int sock)
1064 int command;
1066 msock = sock;
1067 quit_server = 0;
1069 check_version ();
1070 do {
1071 if (rpc_get (sock, RPC_INT, &command, RPC_END) &&
1072 (logged_in || command == MC_LOGIN))
1073 exec_command (command);
1074 } while (!quit_server);
1077 /* }}} */
1079 /* {{{ Net support code */
1081 static char *get_client (int portnum)
1083 int sock, clilen, newsocket;
1084 struct sockaddr_in client_address, server_address;
1085 struct hostent *hp;
1086 char hostname [255];
1087 int yes = 1;
1088 #ifdef __EMX__
1089 char *me;
1090 #endif
1092 if ((sock = socket (AF_INET, SOCK_STREAM, 0)) < 0)
1093 return "Cannot create socket";
1095 /* Use this to debug: */
1096 if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (char *) &yes, sizeof (yes)) < 0)
1097 return "setsockopt failed";
1099 gethostname (hostname, 255);
1100 if (verbose) printf ("hostname=%s\n", hostname);
1101 hp = gethostbyname (hostname);
1102 #ifdef __EMX__
1103 if (hp == 0 && (me = getenv("HOSTNAME")) && (0 == strcmp(hostname, me)))
1104 hp = gethostbyname ("localhost");
1105 #endif
1106 if (hp == 0)
1107 return "hp = 0!";
1109 memset ((char *) &server_address, 0, sizeof (server_address));
1110 server_address.sin_family = hp->h_addrtype;
1111 server_address.sin_addr.s_addr = htonl (INADDR_ANY);
1112 server_address.sin_port = htons (portnum);
1114 if (bind (sock, (struct sockaddr *) &server_address,
1115 sizeof (server_address)) < 0)
1116 return "Cannot bind";
1118 listen (sock, 5);
1120 for (;;){
1121 int child;
1123 clilen = sizeof (client_address);
1124 newsocket = accept (sock, (struct sockaddr *) &client_address,
1125 &clilen);
1127 if (isDaemon && (child = fork())) {
1128 int status;
1130 close (newsocket);
1131 waitpid (child, &status, 0);
1132 continue;
1135 if (isDaemon && fork()) exit (0);
1137 server (newsocket);
1138 close (newsocket);
1139 return 0;
1143 #ifdef HAVE_PMAP_SET
1144 static void signal_int_handler (int sig)
1146 pmap_unset (RPC_PROGNUM, RPC_PROGVER);
1148 #endif
1150 #ifndef IPPORT_RESERVED
1151 #define IPPORT_RESERVED 1024;
1152 #endif
1154 static int get_port_number (void)
1156 int port = 0;
1158 #ifdef HAVE_RRESVPORT
1159 int start_port = IPPORT_RESERVED;
1161 port = rresvport (&start_port);
1162 if (port == -1){
1163 if (geteuid () == 0){
1164 fprintf (stderr, "Could not bind the server on a reserved port\n");
1165 DO_QUIT_NONVOID (-1);
1167 port = 0;
1169 #endif
1170 if (port)
1171 return port;
1173 port = mcserver_port;
1175 return port;
1178 static void register_port (int portnum, int abort_if_fail)
1180 #ifdef HAVE_PMAP_SET
1181 /* Register our service with the portmapper */
1182 /* protocol: pmap_set (prognum, versnum, protocol, portp) */
1184 if (pmap_set (RPC_PROGNUM, RPC_PROGVER, IPPROTO_TCP, portnum))
1185 signal (SIGINT, signal_int_handler);
1186 else {
1187 fprintf (stderr, "Could not register service with portmapper\n");
1188 if (abort_if_fail)
1189 exit (1);
1191 #else
1192 if (abort_if_fail){
1193 fprintf (stderr,
1194 "This system lacks port registration, try using the -p\n"
1195 "flag to force installation at a given port");
1197 #endif
1200 /* }}} */
1202 int main (int argc, char *argv [])
1204 char *result;
1205 extern char *optarg;
1206 int c;
1208 while ((c = getopt (argc, argv, "fdiqp:v")) != -1){
1209 switch (c){
1210 case 'd':
1211 isDaemon = 1;
1212 verbose = 0;
1213 break;
1215 case 'v':
1216 verbose = 1;
1217 break;
1219 case 'f':
1220 ftp = 1;
1221 break;
1223 case 'q':
1224 verbose = 0;
1225 break;
1227 case 'p':
1228 portnum = atoi (optarg);
1229 break;
1231 case 'i':
1232 inetd_started = 1;
1233 break;
1235 case 'r':
1236 r_auth = 1;
1237 break;
1239 default:
1240 fprintf (stderr, "Usage is: mcserv [options] [-p portnum]\n\n"
1241 "options are:\n"
1242 "-d become a daemon (sets -q)\n"
1243 "-q quiet mode\n"
1244 /* "-r use rhost based authentication\n" */
1245 #ifndef HAVE_PAM
1246 "-f force ftp authentication\n"
1247 #endif
1248 "-v verbose mode\n"
1249 "-p to specify a port number to listen\n");
1250 exit (0);
1255 if (isDaemon && fork()) exit (0);
1257 if (portnum == 0)
1258 portnum = get_port_number ();
1260 if (portnum != -1) {
1261 register_port (portnum, 0);
1262 if (verbose)
1263 printf ("Using port %d\n", portnum);
1264 if ((result = get_client (portnum)))
1265 perror (result);
1266 #ifdef HAVE_PMAP_SET
1267 if (!isDaemon)
1268 pmap_unset (RPC_PROGNUM, RPC_PROGVER);
1269 #endif
1271 exit (return_code);
1274 /* FIXME: This function should not be used in mcserv */
1275 void vfs_die( char *m )
1277 fputs (m, stderr);
1278 exit (1);