translated some forgotten messages...
[midnight-commander.git] / vfs / mcserv.c
blob174866c2a6c5a27d0bd4bb761807f4eb4109228c
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 <string.h>
41 #ifdef HAVE_LIMITS_H
42 # include <limits.h>
43 #endif
44 #ifndef NGROUPS_MAX
45 # include <sys/param.h>
46 # ifdef NGROUPS
47 # define NGROUPS_MAX NGROUPS
48 # endif
49 #endif
50 #ifdef HAVE_GRP_H
51 # include <grp.h>
52 #endif
53 #include <sys/types.h>
54 #include <sys/stat.h>
55 #include <sys/wait.h>
56 #include <errno.h>
57 #include <signal.h>
59 /* Network include files */
60 #include <sys/socket.h>
61 #include <netinet/in.h>
62 #include <netdb.h>
63 #ifdef HAVE_ARPA_INET_H
64 #include <arpa/inet.h>
65 #endif
66 #ifdef HAVE_PMAP_SET
67 # include <rpc/rpc.h>
68 # include <rpc/pmap_prot.h>
69 # ifdef HAVE_RPC_PMAP_CLNT_H
70 # include <rpc/pmap_clnt.h>
71 # endif
72 #endif
74 /* Authentication include files */
75 #include <pwd.h>
76 #ifdef HAVE_PAM
77 # include <security/pam_misc.h>
78 # ifndef PAM_ESTABLISH_CRED
79 # define PAM_ESTABLISH_CRED PAM_CRED_ESTABLISH
80 # endif
81 #else
82 #ifdef HAVE_CRYPT_H
83 # include <crypt.h>
84 #else
85 extern char *crypt (const char *, const char *);
86 #endif /* !HAVE_CRYPT_H */
87 #endif /* !HAVE_PAM */
89 #include "utilvfs.h"
91 #include "vfs.h"
92 #include "mcfs.h"
93 #include "tcputil.h"
95 /* The socket from which we accept commands */
96 int msock;
98 /* Requested version number from client */
99 static int clnt_version;
101 /* If non zero, we accept further commands */
102 int logged_in = 0;
104 /* Home directory */
105 char *home_dir = NULL;
107 char *up_dir = NULL;
109 /* Were we started from inetd? */
110 int inetd_started = 0;
112 /* Are we running as a daemon? */
113 int isDaemon = 0;
115 /* guess */
116 int verbose = 0;
118 /* ftp auth */
119 int ftp = 0;
121 /* port number in which we listen to connections,
122 * if zero, we try to contact the portmapper to get a port, and
123 * if it's not possible, then we use a hardcoded value
125 int portnum = 0;
127 /* if the server will use rcmd based authentication (hosts.equiv .rhosts) */
128 int r_auth = 0;
130 #define OPENDIR_HANDLES 8
132 #define DO_QUIT_VOID() \
133 do { \
134 quit_server = 1; \
135 return_code = 1; \
136 return; \
137 } while (0)
139 /* Only used by get_port_number */
140 #define DO_QUIT_NONVOID(a) \
141 do { \
142 quit_server = 1; \
143 return_code = 1; \
144 return (a); \
145 } while (0)
147 char buffer [4096];
148 int debug = 1;
149 static int quit_server;
150 static int return_code;
152 /* }}} */
154 /* {{{ Misc routines */
156 static void send_status (int status, int errno_number)
158 rpc_send (msock, RPC_INT, status, RPC_INT, errno_number, RPC_END);
159 errno = 0;
162 /* }}} */
164 /* {{{ File with handle operations */
166 static void do_open (void)
168 int handle, flags, mode;
169 char *arg;
171 rpc_get (msock, RPC_STRING, &arg, RPC_INT, &flags, RPC_INT, &mode,RPC_END);
173 handle = open (arg, flags, mode);
174 send_status (handle, errno);
175 g_free (arg);
178 static void do_read (void)
180 int handle, count, n;
181 void *data;
183 rpc_get (msock, RPC_INT, &handle, RPC_INT, &count, RPC_END);
184 data = g_malloc (count);
185 if (!data){
186 send_status (-1, ENOMEM);
187 return;
189 if (verbose) printf ("count=%d\n", count);
190 n = read (handle, data, count);
191 if (verbose) printf ("result=%d\n", n);
192 if (n < 0){
193 send_status (-1, errno);
194 return;
196 send_status (n, 0);
197 rpc_send (msock, RPC_BLOCK, n, data, RPC_END);
199 g_free (data);
202 static void do_write (void)
204 int handle, count, status, written = 0;
205 char buf[8192];
207 rpc_get (msock, RPC_INT, &handle, RPC_INT, &count, RPC_END);
208 status = 0;
209 while (count) {
210 int nbytes = count > 8192 ? 8192 : count;
212 rpc_get (msock, RPC_BLOCK, nbytes, buf, RPC_END);
213 status = write (handle, buf, nbytes);
214 if (status < 0) {
215 send_status (status, errno);
216 return;
218 /* FIXED: amount written must be returned to caller */
219 written += status;
220 if (status < nbytes) {
221 send_status (written, errno);
222 return;
224 count -= nbytes;
226 send_status (written, errno);
229 static void do_lseek (void)
231 int handle, offset, whence, status;
233 rpc_get (msock,
234 RPC_INT, &handle,
235 RPC_INT, &offset,
236 RPC_INT, &whence, RPC_END);
237 status = lseek (handle, offset, whence);
238 send_status (status, errno);
241 static void do_close (void)
243 int handle, status;
245 rpc_get (msock, RPC_INT, &handle, RPC_END);
246 status = close (handle);
247 send_status (status, errno);
250 /* }}} */
252 /* {{{ Stat family routines */
254 static void send_time (int sock, time_t time)
256 if (clnt_version == 1) {
257 char *ct;
258 int month;
260 ct = ctime (&time);
261 ct [3] = ct [10] = ct [13] = ct [16] = ct [19] = 0;
263 /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
264 if (ct [4] == 'J'){
265 if (ct [5] == 'a'){
266 month = 0;
267 } else
268 month = (ct [6] == 'n') ? 5 : 6;
269 } else if (ct [4] == 'F'){
270 month = 1;
271 } else if (ct [4] == 'M'){
272 month = (ct [6] == 'r') ? 2 : 5;
273 } else if (ct [4] == 'A'){
274 month = (ct [5] == 'p') ? 3 : 7;
275 } else if (ct [4] == 'S'){
276 month = 8;
277 } else if (ct [4] == 'O'){
278 month = 9;
279 } else if (ct [4] == 'N'){
280 month = 10;
281 } else
282 month = 11;
283 rpc_send (msock,
284 RPC_INT, atoi (&ct [17]), /* sec */
285 RPC_INT, atoi (&ct [14]), /* min */
286 RPC_INT, atoi (&ct [11]), /* hour */
287 RPC_INT, atoi (&ct [8]), /* mday */
288 RPC_INT, atoi (&ct [20]), /* year */
289 RPC_INT, month, /* month */
290 RPC_END);
291 } else {
292 long ltime = (long) time;
293 char buf[BUF_SMALL];
295 g_snprintf (buf, sizeof(buf), "%lx", ltime);
296 rpc_send (msock,
297 RPC_STRING, buf,
298 RPC_END);
302 static void send_stat_info (struct stat *st)
304 long mylong;
305 int blocks =
306 #ifdef HAVE_ST_BLOCKS
307 st->st_blocks;
308 #else
309 st->st_size / 1024;
310 #endif
312 #ifdef HAVE_ST_RDEV
313 mylong = st->st_rdev;
314 #else
315 mylong = 0;
316 #endif
317 rpc_send (msock, RPC_INT, (long) mylong,
318 RPC_INT, (long) st->st_ino,
319 RPC_INT, (long) st->st_mode,
320 RPC_INT, (long) st->st_nlink,
321 RPC_INT, (long) st->st_uid,
322 RPC_INT, (long) st->st_gid,
323 RPC_INT, (long) st->st_size,
324 RPC_INT, (long) blocks, RPC_END);
325 send_time (msock, st->st_atime);
326 send_time (msock, st->st_mtime);
327 send_time (msock, st->st_ctime);
330 static void do_lstat (void)
332 struct stat st;
333 char *file;
334 int n;
336 rpc_get (msock, RPC_STRING, &file, RPC_END);
337 n = lstat (file, &st);
338 send_status (n, errno);
339 if (n >= 0)
340 send_stat_info (&st);
341 g_free (file);
344 static void do_fstat (void)
346 int handle;
347 int n;
348 struct stat st;
350 rpc_get (msock, RPC_INT, &handle, RPC_END);
351 n = fstat (handle, &st);
352 send_status (n, errno);
353 if (n < 0)
354 return;
356 send_stat_info (&st);
359 static void do_stat (void)
361 struct stat st;
362 int n;
363 char *file;
365 rpc_get (msock, RPC_STRING, &file, RPC_END);
367 n = stat (file, &st);
368 send_status (n, errno);
369 if (n >= 0)
370 send_stat_info (&st);
371 g_free (file);
374 /* }}} */
376 /* {{{ Directory lookup operations */
378 static struct {
379 int used;
380 DIR *dirs [OPENDIR_HANDLES];
381 char *names [OPENDIR_HANDLES];
382 } mcfs_DIR;
384 static void close_handle (int handle)
386 if (mcfs_DIR.used > 0) mcfs_DIR.used--;
387 if (mcfs_DIR.dirs [handle])
388 closedir (mcfs_DIR.dirs [handle]);
389 if (mcfs_DIR.names [handle])
390 g_free (mcfs_DIR.names [handle]);
391 mcfs_DIR.dirs [handle] = 0;
392 mcfs_DIR.names [handle] = 0;
395 static void do_opendir (void)
397 int handle, i;
398 char *arg;
399 DIR *p;
401 rpc_get (msock, RPC_STRING, &arg, RPC_END);
403 if (mcfs_DIR.used == OPENDIR_HANDLES){
404 send_status (-1, ENFILE); /* Error */
405 g_free (arg);
406 return;
409 handle = -1;
410 for (i = 0; i < OPENDIR_HANDLES; i++){
411 if (mcfs_DIR.dirs [i] == 0){
412 handle = i;
413 break;
417 if (handle == -1){
418 send_status (-1, EMFILE);
419 g_free (arg);
420 if (!inetd_started)
421 fprintf (stderr, "OOPS! you have found a bug in mc - do_opendir()!\n");
422 return;
425 if (verbose) printf ("handle=%d\n", handle);
426 p = opendir (arg);
427 if (p){
428 mcfs_DIR.dirs [handle] = p;
429 mcfs_DIR.names [handle] = arg;
430 mcfs_DIR.used ++;
432 /* Because 0 is an error value */
433 rpc_send (msock, RPC_INT, handle+1, RPC_INT, 0, RPC_END);
435 } else {
436 send_status (-1, errno);
437 g_free (arg);
441 /* Sends the complete directory listing, as well as the stat information */
442 static void do_readdir (void)
444 struct dirent *dirent;
445 struct stat st;
446 int handle, n;
447 char *fname = 0;
449 rpc_get (msock, RPC_INT, &handle, RPC_END);
451 if (!handle){
452 rpc_send (msock, RPC_INT, 0, RPC_END);
453 return;
456 /* We incremented it in opendir */
457 handle --;
459 while ((dirent = readdir (mcfs_DIR.dirs [handle]))){
460 int length = NLENGTH (dirent);
462 rpc_send (msock, RPC_INT, length, RPC_END);
463 rpc_send (msock, RPC_BLOCK, length, dirent->d_name, RPC_END);
464 fname = g_strconcat (mcfs_DIR.names [handle],
465 PATH_SEP_STR, dirent->d_name, NULL);
466 n = lstat (fname, &st);
467 send_status (n, errno);
468 g_free (fname);
469 if (n >= 0)
470 send_stat_info (&st);
472 rpc_send (msock, RPC_INT, 0, RPC_END);
475 static void do_closedir (void)
477 int handle;
479 rpc_get (msock, RPC_INT, &handle, RPC_END);
480 close_handle (handle-1);
483 /* }}} */
485 /* {{{ Operations with one and two file name argument */
487 static void do_chdir (void)
489 char *file;
490 int status;
492 rpc_get (msock, RPC_STRING, &file, RPC_END);
494 status = chdir (file);
495 send_status (status, errno);
496 g_free (file);
499 static void do_rmdir (void)
501 char *file;
502 int status;
504 rpc_get (msock, RPC_STRING, &file, RPC_END);
506 status = rmdir (file);
507 send_status (status, errno);
508 g_free (file);
511 static void do_mkdir (void)
513 char *file;
514 int mode, status;
516 rpc_get (msock, RPC_STRING, &file, RPC_INT, &mode, RPC_END);
518 status = mkdir (file, mode);
519 send_status (status, errno);
520 g_free (file);
523 static void do_mknod (void)
525 char *file;
526 int mode, dev, status;
528 rpc_get (msock, RPC_STRING, &file, RPC_INT, &mode, RPC_INT, &dev, RPC_END);
530 status = mknod (file, mode, dev);
531 send_status (status, errno);
532 g_free (file);
535 static void do_readlink (void)
537 char buffer [2048];
538 char *file;
539 int n;
541 rpc_get (msock, RPC_STRING, &file, RPC_END);
542 n = readlink (file, buffer, 2048);
543 send_status (n, errno);
544 if (n >= 0) {
545 buffer [n] = 0;
546 rpc_send (msock, RPC_STRING, buffer, RPC_END);
548 g_free (file);
551 static void do_unlink (void)
553 char *file;
554 int status;
556 rpc_get (msock, RPC_STRING, &file, RPC_END);
557 status = unlink (file);
558 send_status (status, errno);
559 g_free (file);
562 static void do_rename (void)
564 char *f1, *f2;
565 int status;
567 rpc_get (msock, RPC_STRING, &f1, RPC_STRING, &f2, RPC_END);
568 status = rename (f1, f2);
569 send_status (status, errno);
570 g_free (f1); g_free (f2);
573 static void do_symlink (void)
575 char *f1, *f2;
576 int status;
578 rpc_get (msock, RPC_STRING, &f1, RPC_STRING, &f2, RPC_END);
579 status = symlink (f1, f2);
580 send_status (status, errno);
581 g_free (f1); g_free (f2);
584 static void do_link (void)
586 char *f1, *f2;
587 int status;
589 rpc_get (msock, RPC_STRING, &f1, RPC_STRING, &f2, RPC_END);
590 status = link (f1, f2);
591 send_status (status, errno);
592 g_free (f1); g_free (f2);
596 /* }}} */
598 /* {{{ Misc commands */
600 static void do_gethome (void)
602 rpc_send (msock, RPC_STRING, (home_dir) ? home_dir : "/", RPC_END);
605 static void do_getupdir (void)
607 rpc_send (msock, RPC_STRING, (up_dir) ? up_dir : "/", RPC_END);
610 static void do_chmod (void)
612 char *file;
613 int mode, status;
615 rpc_get (msock, RPC_STRING, &file, RPC_INT, &mode, RPC_END);
616 status = chmod (file, mode);
617 send_status (status, errno);
618 g_free (file);
621 static void do_chown (void)
623 char *file;
624 int owner, group, status;
626 rpc_get (msock, RPC_STRING, &file,RPC_INT, &owner, RPC_INT,&group,RPC_END);
627 status = chown (file, owner, group);
628 send_status (status, errno);
629 g_free (file);
632 static void do_utime (void)
634 char *file;
635 int status;
636 long atime;
637 long mtime;
638 char *as;
639 char *ms;
640 struct utimbuf times;
642 rpc_get (msock, RPC_STRING, &file,
643 RPC_STRING, &as,
644 RPC_STRING, &ms,
645 RPC_END);
646 sscanf (as, "%lx", &atime);
647 sscanf (ms, "%lx", &mtime);
648 if (verbose) printf ("Got a = %s, m = %s, comp a = %ld, m = %ld\n",
649 as, ms, atime, mtime);
650 g_free (as);
651 g_free (ms);
652 times.actime = (time_t) atime;
653 times.modtime = (time_t) mtime;
654 status = utime (file, &times);
655 send_status (status, errno);
656 g_free (file);
659 static void do_quit (void)
661 quit_server = 1;
664 #ifdef HAVE_PAM
666 struct user_pass {
667 char *username;
668 char *password;
671 static int
672 mc_pam_conversation (int messages, const struct pam_message **msg,
673 struct pam_response **resp, void *appdata_ptr)
675 struct pam_response *r;
676 struct user_pass *up = appdata_ptr;
677 int status;
679 r = g_new (struct pam_response, messages);
680 if (!r)
681 return PAM_CONV_ERR;
682 *resp = r;
684 for (status = PAM_SUCCESS; messages--; msg++, r++){
685 switch ((*msg)->msg_style){
687 case PAM_PROMPT_ECHO_ON:
688 r->resp = g_strdup (up->username);
689 r->resp_retcode = PAM_SUCCESS;
690 break;
692 case PAM_PROMPT_ECHO_OFF:
693 r->resp = g_strdup (up->password);
694 r->resp_retcode = PAM_SUCCESS;
695 break;
697 case PAM_ERROR_MSG:
698 r->resp = NULL;
699 r->resp_retcode = PAM_SUCCESS;
700 break;
702 case PAM_TEXT_INFO:
703 r->resp = NULL;
704 r->resp_retcode = PAM_SUCCESS;
705 break;
708 return status;
711 static struct pam_conv conv = { &mc_pam_conversation, NULL };
714 /* Return 0 if authentication failed, 1 otherwise */
715 static int
716 mc_pam_auth (char *username, char *password)
718 pam_handle_t *pamh;
719 struct user_pass up;
720 int status;
722 up.username = username;
723 up.password = password;
724 conv.appdata_ptr = &up;
726 if ((status = pam_start("mcserv", username, &conv, &pamh)) != PAM_SUCCESS)
727 goto failed_pam;
728 if ((status = pam_authenticate (pamh, 0)) != PAM_SUCCESS)
729 goto failed_pam;
730 if ((status = pam_acct_mgmt (pamh, 0)) != PAM_SUCCESS)
731 goto failed_pam;
732 if ((status = pam_setcred (pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS)
733 goto failed_pam;
734 pam_end (pamh, status);
735 return 0;
737 failed_pam:
738 pam_end (pamh, status);
739 return 1;
742 #else /* Code for non-PAM authentication */
744 /* Keep reading until we find a \n */
745 static int next_line (int socket)
747 char c;
749 while (1){
750 if (read (socket, &c, 1) <= 0)
751 return 0;
752 if (c == '\n')
753 return 1;
757 static int ftp_answer (int sock, char *text)
759 char answer [4];
761 next_line (sock);
762 socket_read_block (sock, answer, 3);
763 answer [3] = 0;
764 if (strcmp (answer, text) == 0)
765 return 1;
766 return 0;
769 static int do_ftp_auth (char *username, char *password)
771 struct sockaddr_in local_address;
772 unsigned long inaddr;
773 int my_socket;
774 char answer [4];
776 memset ((char *) &local_address, 0, sizeof (local_address));
778 local_address.sin_family = AF_INET;
779 /* FIXME: extract the ftp port with the proper function */
780 local_address.sin_port = htons (21);
782 /* Convert localhost to usable format */
783 if ((inaddr = inet_addr ("127.0.0.1")) != -1)
784 memcpy ((char *) &local_address.sin_addr, (char *) &inaddr,
785 sizeof (inaddr));
787 if ((my_socket = socket (AF_INET, SOCK_STREAM, 0)) < 0){
788 if (!isDaemon) fprintf (stderr, "do_auth: can't create socket\n");
789 return 0;
791 if (connect (my_socket, (struct sockaddr *) &local_address,
792 sizeof (local_address)) < 0){
793 fprintf (stderr,
794 "do_auth: can't connect to ftp daemon for authentication\n");
795 close (my_socket);
796 return 0;
798 send_string (my_socket, "user ");
799 send_string (my_socket, username);
800 send_string (my_socket, "\r\n");
801 if (!ftp_answer (my_socket, "331")){
802 send_string (my_socket, "quit\r\n");
803 close (my_socket);
804 return 0;
806 next_line (my_socket); /* Eat all the line */
807 send_string (my_socket, "pass ");
808 send_string (my_socket, password);
809 send_string (my_socket, "\r\n");
810 socket_read_block (my_socket, answer, 3);
811 answer [3] = 0;
812 send_string (my_socket, "\r\n");
813 send_string (my_socket, "quit\r\n");
814 close (my_socket);
815 if (strcmp (answer, "230") == 0)
816 return 1;
817 return 0;
820 static int do_classic_auth (char *username, char *password)
822 struct passwd *this;
823 int ret;
825 if ((this = getpwnam (username)) == 0)
826 return 0;
828 #ifdef HAVE_CRYPT
829 if (strcmp (crypt (password, this->pw_passwd), this->pw_passwd) == 0){
830 ret = 1;
831 } else
832 #endif
834 ret = 0;
836 endpwent ();
837 return ret;
839 #endif /* non-PAM authentication */
841 /* Try to authenticate the user based on:
842 - PAM if the system has it, else it checks:
843 - pwdauth if the system supports it.
844 - conventional auth (check salt on /etc/passwd, crypt, and compare
845 - try to contact the local ftp server and login (if -f flag used)
847 static int
848 do_auth (char *username, char *password)
850 int auth = 0;
851 struct passwd *this;
853 if (strcmp (username, "anonymous") == 0)
854 username = "ftp";
856 #ifdef HAVE_PAM
857 if (mc_pam_auth (username, password) == 0)
858 auth = 1;
859 #else /* if there is no pam */
860 #ifdef HAVE_PWDAUTH
861 if (pwdauth (username, password) == 0)
862 auth = 1;
863 else
864 #endif
865 if (do_classic_auth (username, password))
866 auth = 1;
867 else if (ftp)
868 auth = do_ftp_auth (username, password);
869 #endif /* not pam */
871 if (!auth)
872 return 0;
874 this = getpwnam (username);
875 if (this == 0)
876 return 0;
878 if (chdir (this->pw_dir) == -1)
879 return 0;
881 if (this->pw_dir [strlen (this->pw_dir) - 1] == '/')
882 home_dir = g_strdup (this->pw_dir);
883 else {
884 home_dir = g_malloc (strlen (this->pw_dir) + 2);
885 if (home_dir) {
886 strcpy (home_dir, this->pw_dir);
887 strcat (home_dir, "/");
888 } else
889 home_dir = "/";
893 if (setgid (this->pw_gid) == -1)
894 return 0;
896 #ifdef HAVE_INITGROUPS
897 #ifdef NGROUPS_MAX
898 if (NGROUPS_MAX > 1 && initgroups (this->pw_name, this->pw_gid))
899 return 0;
900 #endif
901 #endif
903 #if defined (HAVE_SETUID)
904 if (setuid (this->pw_uid))
905 return 0;
906 #elif defined (HAVE_SETREUID)
907 if (setreuid (this->pw_uid, this->pw_uid))
908 return 0;
909 #endif
911 /* If the setuid call failed, then deny access */
912 /* This should fix the problem on those machines with strange setups */
913 if (getuid () != this->pw_uid)
914 return 0;
916 if (strcmp (username, "ftp") == 0)
917 chroot (this->pw_dir);
919 endpwent ();
920 return auth;
923 #if 0
924 static int do_rauth (int socket)
926 struct sockaddr_in from;
927 struct hostent *hp;
929 if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0)
930 return 0;
931 from.sin_port = ntohs ((unsigned short) from.sin_port);
933 /* Strange, this should not happend */
934 if (from.sin_family != AF_INET)
935 return 0;
937 hp = gethostbyaddr((char *)&fromp.sin_addr, sizeof (struct in_addr),
938 fromp.sin_family);
941 #endif
943 static int do_rauth (int msock)
945 return 0;
948 static void login_reply (int logged_in)
950 rpc_send (msock, RPC_INT,
951 logged_in ? MC_LOGINOK : MC_INVALID_PASS,
952 RPC_END);
955 /* FIXME: Implement the anonymous login */
956 static void do_login (void)
958 char *username;
959 char *password;
960 int result;
962 rpc_get (msock, RPC_LIMITED_STRING, &up_dir, RPC_LIMITED_STRING, &username, RPC_END);
963 if (verbose) printf ("username: %s\n", username);
965 if (r_auth){
966 logged_in = do_rauth (msock);
967 if (logged_in){
968 login_reply (logged_in);
969 return;
972 rpc_send (msock, RPC_INT, MC_NEED_PASSWORD, RPC_END);
973 rpc_get (msock, RPC_INT, &result, RPC_END);
974 if (result == MC_QUIT)
975 DO_QUIT_VOID ();
976 if (result != MC_PASS){
977 if (verbose) printf ("do_login: Unknown response: %d\n", result);
978 DO_QUIT_VOID ();
980 rpc_get (msock, RPC_LIMITED_STRING, &password, RPC_END);
981 logged_in = do_auth (username, password);
982 endpwent ();
983 login_reply (logged_in);
986 /* }}} */
988 /* {{{ Server and dispatching functions */
990 /* This structure must be kept in synch with mcfs.h enums */
992 static struct _command {
993 char *command;
994 void (*callback)(void);
995 } commands [] = {
996 { "open", do_open },
997 { "close", do_close },
998 { "read", do_read },
999 { "write", do_write },
1000 { "opendir", do_opendir },
1001 { "readdir", do_readdir },
1002 { "closedir", do_closedir },
1003 { "stat ", do_stat },
1004 { "lstat ", do_lstat },
1005 { "fstat", do_fstat },
1006 { "chmod", do_chmod },
1007 { "chown", do_chown },
1008 { "readlink ", do_readlink },
1009 { "unlink", do_unlink },
1010 { "rename", do_rename },
1011 { "chdir ", do_chdir },
1012 { "lseek", do_lseek },
1013 { "rmdir", do_rmdir },
1014 { "symlink", do_symlink },
1015 { "mknod", do_mknod },
1016 { "mkdir", do_mkdir },
1017 { "link", do_link },
1018 { "gethome", do_gethome },
1019 { "getupdir", do_getupdir },
1020 { "login", do_login },
1021 { "quit", do_quit },
1022 { "utime", do_utime },
1025 static int ncommands = sizeof(commands)/sizeof(struct _command);
1027 static void exec_command (int command)
1029 if (command < 0 ||
1030 command >= ncommands ||
1031 commands [command].command == 0){
1032 fprintf (stderr, "Got unknown command: %d\n", command);
1033 DO_QUIT_VOID ();
1035 if (verbose) printf ("Command: %s\n", commands [command].command);
1036 (*commands [command].callback)();
1039 static void check_version (void)
1041 int version;
1043 rpc_get (msock, RPC_INT, &version, RPC_END);
1044 if (version >= 1 &&
1045 version <= RPC_PROGVER)
1046 rpc_send (msock, RPC_INT, MC_VERSION_OK, RPC_END);
1047 else
1048 rpc_send (msock, RPC_INT, MC_VERSION_MISMATCH, RPC_END);
1050 clnt_version = version;
1053 /* This routine is called by rpc_get/rpc_send when the connection is closed */
1054 void tcp_invalidate_socket (int sock)
1056 if (verbose) printf ("Connection closed\n");
1057 DO_QUIT_VOID();
1060 static void server (int sock)
1062 int command;
1064 msock = sock;
1065 quit_server = 0;
1067 check_version ();
1068 do {
1069 if (rpc_get (sock, RPC_INT, &command, RPC_END) &&
1070 (logged_in || command == MC_LOGIN))
1071 exec_command (command);
1072 } while (!quit_server);
1075 /* }}} */
1077 /* {{{ Net support code */
1079 static char *get_client (int portnum)
1081 int sock, clilen, newsocket;
1082 struct sockaddr_in client_address, server_address;
1083 struct hostent *hp;
1084 char hostname [255];
1085 int yes = 1;
1086 #ifdef __EMX__
1087 char *me;
1088 #endif
1090 if ((sock = socket (AF_INET, SOCK_STREAM, 0)) < 0)
1091 return "Cannot create socket";
1093 /* Use this to debug: */
1094 if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (char *) &yes, sizeof (yes)) < 0)
1095 return "setsockopt failed";
1097 gethostname (hostname, 255);
1098 if (verbose) printf ("hostname=%s\n", hostname);
1099 hp = gethostbyname (hostname);
1100 #ifdef __EMX__
1101 if (hp == 0 && (me = getenv("HOSTNAME")) && (0 == strcmp(hostname, me)))
1102 hp = gethostbyname ("localhost");
1103 #endif
1104 if (hp == 0)
1105 return "hp = 0!";
1107 memset ((char *) &server_address, 0, sizeof (server_address));
1108 server_address.sin_family = hp->h_addrtype;
1109 server_address.sin_addr.s_addr = htonl (INADDR_ANY);
1110 server_address.sin_port = htons (portnum);
1112 if (bind (sock, (struct sockaddr *) &server_address,
1113 sizeof (server_address)) < 0)
1114 return "Cannot bind";
1116 listen (sock, 5);
1118 for (;;){
1119 int child;
1121 clilen = sizeof (client_address);
1122 newsocket = accept (sock, (struct sockaddr *) &client_address,
1123 &clilen);
1125 if (isDaemon && (child = fork())) {
1126 int status;
1128 close (newsocket);
1129 waitpid (child, &status, 0);
1130 continue;
1133 if (isDaemon && fork()) exit (0);
1135 server (newsocket);
1136 close (newsocket);
1137 return 0;
1141 #ifdef HAVE_PMAP_SET
1142 static void signal_int_handler (int sig)
1144 pmap_unset (RPC_PROGNUM, RPC_PROGVER);
1146 #endif
1148 #ifndef IPPORT_RESERVED
1149 #define IPPORT_RESERVED 1024;
1150 #endif
1152 static int get_port_number (void)
1154 int port = 0;
1156 #ifdef HAVE_RRESVPORT
1157 int start_port = IPPORT_RESERVED;
1159 port = rresvport (&start_port);
1160 if (port == -1){
1161 if (geteuid () == 0){
1162 fprintf (stderr, "Could not bind the server on a reserved port\n");
1163 DO_QUIT_NONVOID (-1);
1165 port = 0;
1167 #endif
1168 if (port)
1169 return port;
1171 port = mcserver_port;
1173 return port;
1176 static void register_port (int portnum, int abort_if_fail)
1178 #ifdef HAVE_PMAP_SET
1179 /* Register our service with the portmapper */
1180 /* protocol: pmap_set (prognum, versnum, protocol, portp) */
1182 if (pmap_set (RPC_PROGNUM, RPC_PROGVER, IPPROTO_TCP, portnum))
1183 signal (SIGINT, signal_int_handler);
1184 else {
1185 fprintf (stderr, "Could not register service with portmapper\n");
1186 if (abort_if_fail)
1187 exit (1);
1189 #else
1190 if (abort_if_fail){
1191 fprintf (stderr,
1192 "This system lacks port registration, try using the -p\n"
1193 "flag to force installation at a given port");
1195 #endif
1198 /* }}} */
1200 int main (int argc, char *argv [])
1202 char *result;
1203 extern char *optarg;
1204 int c;
1206 while ((c = getopt (argc, argv, "fdiqp:v")) != -1){
1207 switch (c){
1208 case 'd':
1209 isDaemon = 1;
1210 verbose = 0;
1211 break;
1213 case 'v':
1214 verbose = 1;
1215 break;
1217 case 'f':
1218 ftp = 1;
1219 break;
1221 case 'q':
1222 verbose = 0;
1223 break;
1225 case 'p':
1226 portnum = atoi (optarg);
1227 break;
1229 case 'i':
1230 inetd_started = 1;
1231 break;
1233 case 'r':
1234 r_auth = 1;
1235 break;
1237 default:
1238 fprintf (stderr, "Usage is: mcserv [options] [-p portnum]\n\n"
1239 "options are:\n"
1240 "-d become a daemon (sets -q)\n"
1241 "-q quiet mode\n"
1242 /* "-r use rhost based authentication\n" */
1243 #ifndef HAVE_PAM
1244 "-f force ftp authentication\n"
1245 #endif
1246 "-v verbose mode\n"
1247 "-p to specify a port number to listen\n");
1248 exit (0);
1253 if (isDaemon && fork()) exit (0);
1255 if (portnum == 0)
1256 portnum = get_port_number ();
1258 if (portnum != -1) {
1259 register_port (portnum, 0);
1260 if (verbose)
1261 printf ("Using port %d\n", portnum);
1262 if ((result = get_client (portnum)))
1263 perror (result);
1264 #ifdef HAVE_PMAP_SET
1265 if (!isDaemon)
1266 pmap_unset (RPC_PROGNUM, RPC_PROGVER);
1267 #endif
1269 exit (return_code);
1272 /* FIXME: This function should not be used in mcserv */
1273 void vfs_die( char *m )
1275 fputs (m, stderr);
1276 exit (1);