translated tartially 'til file operations...
[midnight-commander.git] / vfs / mcserv.c
blobbbe2c1fae13795d38203542e1fe3b20f214a9d0a
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 #include <sys/types.h>
55 #include <sys/stat.h>
56 #include <sys/wait.h>
57 #include <errno.h>
58 #include <signal.h>
60 /* Network include files */
61 #include <sys/socket.h>
62 #include <netinet/in.h>
63 #include <netdb.h>
64 #ifdef HAVE_ARPA_INET_H
65 #include <arpa/inet.h>
66 #endif
67 #ifdef HAVE_PMAP_SET
68 # include <rpc/rpc.h>
69 # include <rpc/pmap_prot.h>
70 # ifdef HAVE_RPC_PMAP_CLNT_H
71 # include <rpc/pmap_clnt.h>
72 # endif
73 #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 #else
83 #ifdef HAVE_CRYPT_H
84 # include <crypt.h>
85 #else
86 extern char *crypt (const char *, const char *);
87 #endif /* !HAVE_CRYPT_H */
88 #endif /* !HAVE_PAM */
90 #include "utilvfs.h"
92 #include "vfs.h"
93 #include "mcfs.h"
94 #include "tcputil.h"
96 /* The socket from which we accept commands */
97 int msock;
99 /* Requested version number from client */
100 static int clnt_version;
102 /* If non zero, we accept further commands */
103 int logged_in = 0;
105 /* Home directory */
106 char *home_dir = NULL;
108 char *up_dir = NULL;
110 /* Were we started from inetd? */
111 int inetd_started = 0;
113 /* Are we running as a daemon? */
114 int isDaemon = 0;
116 /* guess */
117 int verbose = 0;
119 /* ftp auth */
120 int ftp = 0;
122 /* port number in which we listen to connections,
123 * if zero, we try to contact the portmapper to get a port, and
124 * if it's not possible, then we use a hardcoded value
126 int portnum = 0;
128 /* if the server will use rcmd based authentication (hosts.equiv .rhosts) */
129 int r_auth = 0;
131 #define OPENDIR_HANDLES 8
133 #define DO_QUIT_VOID() \
134 do { \
135 quit_server = 1; \
136 return_code = 1; \
137 return; \
138 } while (0)
140 /* Only used by get_port_number */
141 #define DO_QUIT_NONVOID(a) \
142 do { \
143 quit_server = 1; \
144 return_code = 1; \
145 return (a); \
146 } while (0)
148 char buffer [4096];
149 int debug = 1;
150 static int quit_server;
151 static int return_code;
153 /* }}} */
155 /* {{{ Misc routines */
157 static void send_status (int status, int errno_number)
159 rpc_send (msock, RPC_INT, status, RPC_INT, errno_number, RPC_END);
160 errno = 0;
163 /* }}} */
165 /* {{{ File with handle operations */
167 static void do_open (void)
169 int handle, flags, mode;
170 char *arg;
172 rpc_get (msock, RPC_STRING, &arg, RPC_INT, &flags, RPC_INT, &mode,RPC_END);
174 handle = open (arg, flags, mode);
175 send_status (handle, errno);
176 g_free (arg);
179 static void do_read (void)
181 int handle, count, n;
182 void *data;
184 rpc_get (msock, RPC_INT, &handle, RPC_INT, &count, RPC_END);
185 data = g_malloc (count);
186 if (!data){
187 send_status (-1, ENOMEM);
188 return;
190 if (verbose) printf ("count=%d\n", count);
191 n = read (handle, data, count);
192 if (verbose) printf ("result=%d\n", n);
193 if (n < 0){
194 send_status (-1, errno);
195 return;
197 send_status (n, 0);
198 rpc_send (msock, RPC_BLOCK, n, data, RPC_END);
200 g_free (data);
203 static void do_write (void)
205 int handle, count, status, written = 0;
206 char buf[8192];
208 rpc_get (msock, RPC_INT, &handle, RPC_INT, &count, RPC_END);
209 status = 0;
210 while (count) {
211 int nbytes = count > 8192 ? 8192 : count;
213 rpc_get (msock, RPC_BLOCK, nbytes, buf, RPC_END);
214 status = write (handle, buf, nbytes);
215 if (status < 0) {
216 send_status (status, errno);
217 return;
219 /* FIXED: amount written must be returned to caller */
220 written += status;
221 if (status < nbytes) {
222 send_status (written, errno);
223 return;
225 count -= nbytes;
227 send_status (written, errno);
230 static void do_lseek (void)
232 int handle, offset, whence, status;
234 rpc_get (msock,
235 RPC_INT, &handle,
236 RPC_INT, &offset,
237 RPC_INT, &whence, RPC_END);
238 status = lseek (handle, offset, whence);
239 send_status (status, errno);
242 static void do_close (void)
244 int handle, status;
246 rpc_get (msock, RPC_INT, &handle, RPC_END);
247 status = close (handle);
248 send_status (status, errno);
251 /* }}} */
253 /* {{{ Stat family routines */
255 static void send_time (int sock, time_t time)
257 if (clnt_version == 1) {
258 char *ct;
259 int month;
261 ct = ctime (&time);
262 ct [3] = ct [10] = ct [13] = ct [16] = ct [19] = 0;
264 /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
265 if (ct [4] == 'J'){
266 if (ct [5] == 'a'){
267 month = 0;
268 } else
269 month = (ct [6] == 'n') ? 5 : 6;
270 } else if (ct [4] == 'F'){
271 month = 1;
272 } else if (ct [4] == 'M'){
273 month = (ct [6] == 'r') ? 2 : 5;
274 } else if (ct [4] == 'A'){
275 month = (ct [5] == 'p') ? 3 : 7;
276 } else if (ct [4] == 'S'){
277 month = 8;
278 } else if (ct [4] == 'O'){
279 month = 9;
280 } else if (ct [4] == 'N'){
281 month = 10;
282 } else
283 month = 11;
284 rpc_send (msock,
285 RPC_INT, atoi (&ct [17]), /* sec */
286 RPC_INT, atoi (&ct [14]), /* min */
287 RPC_INT, atoi (&ct [11]), /* hour */
288 RPC_INT, atoi (&ct [8]), /* mday */
289 RPC_INT, atoi (&ct [20]), /* year */
290 RPC_INT, month, /* month */
291 RPC_END);
292 } else {
293 long ltime = (long) time;
294 char buf[BUF_SMALL];
296 g_snprintf (buf, sizeof(buf), "%lx", ltime);
297 rpc_send (msock,
298 RPC_STRING, buf,
299 RPC_END);
303 static void send_stat_info (struct stat *st)
305 long mylong;
306 int blocks =
307 #ifdef HAVE_ST_BLOCKS
308 st->st_blocks;
309 #else
310 st->st_size / 1024;
311 #endif
313 #ifdef HAVE_ST_RDEV
314 mylong = st->st_rdev;
315 #else
316 mylong = 0;
317 #endif
318 rpc_send (msock, RPC_INT, (long) mylong,
319 RPC_INT, (long) st->st_ino,
320 RPC_INT, (long) st->st_mode,
321 RPC_INT, (long) st->st_nlink,
322 RPC_INT, (long) st->st_uid,
323 RPC_INT, (long) st->st_gid,
324 RPC_INT, (long) st->st_size,
325 RPC_INT, (long) blocks, RPC_END);
326 send_time (msock, st->st_atime);
327 send_time (msock, st->st_mtime);
328 send_time (msock, st->st_ctime);
331 static void do_lstat (void)
333 struct stat st;
334 char *file;
335 int n;
337 rpc_get (msock, RPC_STRING, &file, RPC_END);
338 n = lstat (file, &st);
339 send_status (n, errno);
340 if (n >= 0)
341 send_stat_info (&st);
342 g_free (file);
345 static void do_fstat (void)
347 int handle;
348 int n;
349 struct stat st;
351 rpc_get (msock, RPC_INT, &handle, RPC_END);
352 n = fstat (handle, &st);
353 send_status (n, errno);
354 if (n < 0)
355 return;
357 send_stat_info (&st);
360 static void do_stat (void)
362 struct stat st;
363 int n;
364 char *file;
366 rpc_get (msock, RPC_STRING, &file, RPC_END);
368 n = stat (file, &st);
369 send_status (n, errno);
370 if (n >= 0)
371 send_stat_info (&st);
372 g_free (file);
375 /* }}} */
377 /* {{{ Directory lookup operations */
379 static struct {
380 int used;
381 DIR *dirs [OPENDIR_HANDLES];
382 char *names [OPENDIR_HANDLES];
383 } mcfs_DIR;
385 static void close_handle (int handle)
387 if (mcfs_DIR.used > 0) mcfs_DIR.used--;
388 if (mcfs_DIR.dirs [handle])
389 closedir (mcfs_DIR.dirs [handle]);
390 if (mcfs_DIR.names [handle])
391 g_free (mcfs_DIR.names [handle]);
392 mcfs_DIR.dirs [handle] = 0;
393 mcfs_DIR.names [handle] = 0;
396 static void do_opendir (void)
398 int handle, i;
399 char *arg;
400 DIR *p;
402 rpc_get (msock, RPC_STRING, &arg, RPC_END);
404 if (mcfs_DIR.used == OPENDIR_HANDLES){
405 send_status (-1, ENFILE); /* Error */
406 g_free (arg);
407 return;
410 handle = -1;
411 for (i = 0; i < OPENDIR_HANDLES; i++){
412 if (mcfs_DIR.dirs [i] == 0){
413 handle = i;
414 break;
418 if (handle == -1){
419 send_status (-1, EMFILE);
420 g_free (arg);
421 if (!inetd_started)
422 fprintf (stderr, "OOPS! you have found a bug in mc - do_opendir()!\n");
423 return;
426 if (verbose) printf ("handle=%d\n", handle);
427 p = opendir (arg);
428 if (p){
429 mcfs_DIR.dirs [handle] = p;
430 mcfs_DIR.names [handle] = arg;
431 mcfs_DIR.used ++;
433 /* Because 0 is an error value */
434 rpc_send (msock, RPC_INT, handle+1, RPC_INT, 0, RPC_END);
436 } else {
437 send_status (-1, errno);
438 g_free (arg);
442 /* Sends the complete directory listing, as well as the stat information */
443 static void do_readdir (void)
445 struct dirent *dirent;
446 struct stat st;
447 int handle, n;
448 char *fname = 0;
450 rpc_get (msock, RPC_INT, &handle, RPC_END);
452 if (!handle){
453 rpc_send (msock, RPC_INT, 0, RPC_END);
454 return;
457 /* We incremented it in opendir */
458 handle --;
460 while ((dirent = readdir (mcfs_DIR.dirs [handle]))){
461 int length = NLENGTH (dirent);
463 rpc_send (msock, RPC_INT, length, RPC_END);
464 rpc_send (msock, RPC_BLOCK, length, dirent->d_name, RPC_END);
465 fname = g_strconcat (mcfs_DIR.names [handle],
466 PATH_SEP_STR, dirent->d_name, NULL);
467 n = lstat (fname, &st);
468 send_status (n, errno);
469 g_free (fname);
470 if (n >= 0)
471 send_stat_info (&st);
473 rpc_send (msock, RPC_INT, 0, RPC_END);
476 static void do_closedir (void)
478 int handle;
480 rpc_get (msock, RPC_INT, &handle, RPC_END);
481 close_handle (handle-1);
484 /* }}} */
486 /* {{{ Operations with one and two file name argument */
488 static void do_chdir (void)
490 char *file;
491 int status;
493 rpc_get (msock, RPC_STRING, &file, RPC_END);
495 status = chdir (file);
496 send_status (status, errno);
497 g_free (file);
500 static void do_rmdir (void)
502 char *file;
503 int status;
505 rpc_get (msock, RPC_STRING, &file, RPC_END);
507 status = rmdir (file);
508 send_status (status, errno);
509 g_free (file);
512 static void do_mkdir (void)
514 char *file;
515 int mode, status;
517 rpc_get (msock, RPC_STRING, &file, RPC_INT, &mode, RPC_END);
519 status = mkdir (file, mode);
520 send_status (status, errno);
521 g_free (file);
524 static void do_mknod (void)
526 char *file;
527 int mode, dev, status;
529 rpc_get (msock, RPC_STRING, &file, RPC_INT, &mode, RPC_INT, &dev, RPC_END);
531 status = mknod (file, mode, dev);
532 send_status (status, errno);
533 g_free (file);
536 static void do_readlink (void)
538 char buffer [2048];
539 char *file;
540 int n;
542 rpc_get (msock, RPC_STRING, &file, RPC_END);
543 n = readlink (file, buffer, 2048);
544 send_status (n, errno);
545 if (n >= 0) {
546 buffer [n] = 0;
547 rpc_send (msock, RPC_STRING, buffer, RPC_END);
549 g_free (file);
552 static void do_unlink (void)
554 char *file;
555 int status;
557 rpc_get (msock, RPC_STRING, &file, RPC_END);
558 status = unlink (file);
559 send_status (status, errno);
560 g_free (file);
563 static void do_rename (void)
565 char *f1, *f2;
566 int status;
568 rpc_get (msock, RPC_STRING, &f1, RPC_STRING, &f2, RPC_END);
569 status = rename (f1, f2);
570 send_status (status, errno);
571 g_free (f1); g_free (f2);
574 static void do_symlink (void)
576 char *f1, *f2;
577 int status;
579 rpc_get (msock, RPC_STRING, &f1, RPC_STRING, &f2, RPC_END);
580 status = symlink (f1, f2);
581 send_status (status, errno);
582 g_free (f1); g_free (f2);
585 static void do_link (void)
587 char *f1, *f2;
588 int status;
590 rpc_get (msock, RPC_STRING, &f1, RPC_STRING, &f2, RPC_END);
591 status = link (f1, f2);
592 send_status (status, errno);
593 g_free (f1); g_free (f2);
597 /* }}} */
599 /* {{{ Misc commands */
601 static void do_gethome (void)
603 rpc_send (msock, RPC_STRING, (home_dir) ? home_dir : "/", RPC_END);
606 static void do_getupdir (void)
608 rpc_send (msock, RPC_STRING, (up_dir) ? up_dir : "/", RPC_END);
611 static void do_chmod (void)
613 char *file;
614 int mode, status;
616 rpc_get (msock, RPC_STRING, &file, RPC_INT, &mode, RPC_END);
617 status = chmod (file, mode);
618 send_status (status, errno);
619 g_free (file);
622 static void do_chown (void)
624 char *file;
625 int owner, group, status;
627 rpc_get (msock, RPC_STRING, &file,RPC_INT, &owner, RPC_INT,&group,RPC_END);
628 status = chown (file, owner, group);
629 send_status (status, errno);
630 g_free (file);
633 static void do_utime (void)
635 char *file;
636 int status;
637 long atime;
638 long mtime;
639 char *as;
640 char *ms;
641 struct utimbuf times;
643 rpc_get (msock, RPC_STRING, &file,
644 RPC_STRING, &as,
645 RPC_STRING, &ms,
646 RPC_END);
647 sscanf (as, "%lx", &atime);
648 sscanf (ms, "%lx", &mtime);
649 if (verbose) printf ("Got a = %s, m = %s, comp a = %ld, m = %ld\n",
650 as, ms, atime, mtime);
651 g_free (as);
652 g_free (ms);
653 times.actime = (time_t) atime;
654 times.modtime = (time_t) mtime;
655 status = utime (file, &times);
656 send_status (status, errno);
657 g_free (file);
660 static void do_quit (void)
662 quit_server = 1;
665 #ifdef HAVE_PAM
667 struct user_pass {
668 char *username;
669 char *password;
672 static int
673 mc_pam_conversation (int messages, const struct pam_message **msg,
674 struct pam_response **resp, void *appdata_ptr)
676 struct pam_response *r;
677 struct user_pass *up = appdata_ptr;
678 int status;
680 r = g_new (struct pam_response, messages);
681 if (!r)
682 return PAM_CONV_ERR;
683 *resp = r;
685 for (status = PAM_SUCCESS; messages--; msg++, r++){
686 switch ((*msg)->msg_style){
688 case PAM_PROMPT_ECHO_ON:
689 r->resp = g_strdup (up->username);
690 r->resp_retcode = PAM_SUCCESS;
691 break;
693 case PAM_PROMPT_ECHO_OFF:
694 r->resp = g_strdup (up->password);
695 r->resp_retcode = PAM_SUCCESS;
696 break;
698 case PAM_ERROR_MSG:
699 r->resp = NULL;
700 r->resp_retcode = PAM_SUCCESS;
701 break;
703 case PAM_TEXT_INFO:
704 r->resp = NULL;
705 r->resp_retcode = PAM_SUCCESS;
706 break;
709 return status;
712 static struct pam_conv conv = { &mc_pam_conversation, NULL };
715 /* Return 0 if authentication failed, 1 otherwise */
716 static int
717 mc_pam_auth (char *username, char *password)
719 pam_handle_t *pamh;
720 struct user_pass up;
721 int status;
723 up.username = username;
724 up.password = password;
725 conv.appdata_ptr = &up;
727 if ((status = pam_start("mcserv", username, &conv, &pamh)) != PAM_SUCCESS)
728 goto failed_pam;
729 if ((status = pam_authenticate (pamh, 0)) != PAM_SUCCESS)
730 goto failed_pam;
731 if ((status = pam_acct_mgmt (pamh, 0)) != PAM_SUCCESS)
732 goto failed_pam;
733 if ((status = pam_setcred (pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS)
734 goto failed_pam;
735 pam_end (pamh, status);
736 return 0;
738 failed_pam:
739 pam_end (pamh, status);
740 return 1;
743 #else /* Code for non-PAM authentication */
745 /* Keep reading until we find a \n */
746 static int next_line (int socket)
748 char c;
750 while (1){
751 if (read (socket, &c, 1) <= 0)
752 return 0;
753 if (c == '\n')
754 return 1;
758 static int ftp_answer (int sock, char *text)
760 char answer [4];
762 next_line (sock);
763 socket_read_block (sock, answer, 3);
764 answer [3] = 0;
765 if (strcmp (answer, text) == 0)
766 return 1;
767 return 0;
770 static int do_ftp_auth (char *username, char *password)
772 struct sockaddr_in local_address;
773 unsigned long inaddr;
774 int my_socket;
775 char answer [4];
777 memset ((char *) &local_address, 0, sizeof (local_address));
779 local_address.sin_family = AF_INET;
780 /* FIXME: extract the ftp port with the proper function */
781 local_address.sin_port = htons (21);
783 /* Convert localhost to usable format */
784 if ((inaddr = inet_addr ("127.0.0.1")) != -1)
785 memcpy ((char *) &local_address.sin_addr, (char *) &inaddr,
786 sizeof (inaddr));
788 if ((my_socket = socket (AF_INET, SOCK_STREAM, 0)) < 0){
789 if (!isDaemon) fprintf (stderr, "do_auth: can't create socket\n");
790 return 0;
792 if (connect (my_socket, (struct sockaddr *) &local_address,
793 sizeof (local_address)) < 0){
794 fprintf (stderr,
795 "do_auth: can't connect to ftp daemon for authentication\n");
796 close (my_socket);
797 return 0;
799 send_string (my_socket, "user ");
800 send_string (my_socket, username);
801 send_string (my_socket, "\r\n");
802 if (!ftp_answer (my_socket, "331")){
803 send_string (my_socket, "quit\r\n");
804 close (my_socket);
805 return 0;
807 next_line (my_socket); /* Eat all the line */
808 send_string (my_socket, "pass ");
809 send_string (my_socket, password);
810 send_string (my_socket, "\r\n");
811 socket_read_block (my_socket, answer, 3);
812 answer [3] = 0;
813 send_string (my_socket, "\r\n");
814 send_string (my_socket, "quit\r\n");
815 close (my_socket);
816 if (strcmp (answer, "230") == 0)
817 return 1;
818 return 0;
821 static int do_classic_auth (char *username, char *password)
823 struct passwd *this;
824 int ret;
826 if ((this = getpwnam (username)) == 0)
827 return 0;
829 #ifdef HAVE_CRYPT
830 if (strcmp (crypt (password, this->pw_passwd), this->pw_passwd) == 0){
831 ret = 1;
832 } else
833 #endif
835 ret = 0;
837 endpwent ();
838 return ret;
840 #endif /* non-PAM authentication */
842 /* Try to authenticate the user based on:
843 - PAM if the system has it, else it checks:
844 - pwdauth if the system supports it.
845 - conventional auth (check salt on /etc/passwd, crypt, and compare
846 - try to contact the local ftp server and login (if -f flag used)
848 static int
849 do_auth (char *username, char *password)
851 int auth = 0;
852 struct passwd *this;
854 if (strcmp (username, "anonymous") == 0)
855 username = "ftp";
857 #ifdef HAVE_PAM
858 if (mc_pam_auth (username, password) == 0)
859 auth = 1;
860 #else /* if there is no pam */
861 #ifdef HAVE_PWDAUTH
862 if (pwdauth (username, password) == 0)
863 auth = 1;
864 else
865 #endif
866 if (do_classic_auth (username, password))
867 auth = 1;
868 else if (ftp)
869 auth = do_ftp_auth (username, password);
870 #endif /* not pam */
872 if (!auth)
873 return 0;
875 this = getpwnam (username);
876 if (this == 0)
877 return 0;
879 if (chdir (this->pw_dir) == -1)
880 return 0;
882 if (this->pw_dir [strlen (this->pw_dir) - 1] == '/')
883 home_dir = g_strdup (this->pw_dir);
884 else {
885 home_dir = g_malloc (strlen (this->pw_dir) + 2);
886 if (home_dir) {
887 strcpy (home_dir, this->pw_dir);
888 strcat (home_dir, "/");
889 } else
890 home_dir = "/";
894 if (setgid (this->pw_gid) == -1)
895 return 0;
897 #ifdef HAVE_INITGROUPS
898 #ifdef NGROUPS_MAX
899 if (NGROUPS_MAX > 1 && initgroups (this->pw_name, this->pw_gid))
900 return 0;
901 #endif
902 #endif
904 #if defined (HAVE_SETUID)
905 if (setuid (this->pw_uid))
906 return 0;
907 #elif defined (HAVE_SETREUID)
908 if (setreuid (this->pw_uid, this->pw_uid))
909 return 0;
910 #endif
912 /* If the setuid call failed, then deny access */
913 /* This should fix the problem on those machines with strange setups */
914 if (getuid () != this->pw_uid)
915 return 0;
917 if (strcmp (username, "ftp") == 0)
918 chroot (this->pw_dir);
920 endpwent ();
921 return auth;
924 #if 0
925 static int do_rauth (int socket)
927 struct sockaddr_in from;
928 struct hostent *hp;
930 if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0)
931 return 0;
932 from.sin_port = ntohs ((unsigned short) from.sin_port);
934 /* Strange, this should not happend */
935 if (from.sin_family != AF_INET)
936 return 0;
938 hp = gethostbyaddr((char *)&fromp.sin_addr, sizeof (struct in_addr),
939 fromp.sin_family);
942 #endif
944 static int do_rauth (int msock)
946 return 0;
949 static void login_reply (int logged_in)
951 rpc_send (msock, RPC_INT,
952 logged_in ? MC_LOGINOK : MC_INVALID_PASS,
953 RPC_END);
956 /* FIXME: Implement the anonymous login */
957 static void do_login (void)
959 char *username;
960 char *password;
961 int result;
963 rpc_get (msock, RPC_LIMITED_STRING, &up_dir, RPC_LIMITED_STRING, &username, RPC_END);
964 if (verbose) printf ("username: %s\n", username);
966 if (r_auth){
967 logged_in = do_rauth (msock);
968 if (logged_in){
969 login_reply (logged_in);
970 return;
973 rpc_send (msock, RPC_INT, MC_NEED_PASSWORD, RPC_END);
974 rpc_get (msock, RPC_INT, &result, RPC_END);
975 if (result == MC_QUIT)
976 DO_QUIT_VOID ();
977 if (result != MC_PASS){
978 if (verbose) printf ("do_login: Unknown response: %d\n", result);
979 DO_QUIT_VOID ();
981 rpc_get (msock, RPC_LIMITED_STRING, &password, RPC_END);
982 logged_in = do_auth (username, password);
983 endpwent ();
984 login_reply (logged_in);
987 /* }}} */
989 /* {{{ Server and dispatching functions */
991 /* This structure must be kept in synch with mcfs.h enums */
993 static struct _command {
994 char *command;
995 void (*callback)(void);
996 } commands [] = {
997 { "open", do_open },
998 { "close", do_close },
999 { "read", do_read },
1000 { "write", do_write },
1001 { "opendir", do_opendir },
1002 { "readdir", do_readdir },
1003 { "closedir", do_closedir },
1004 { "stat ", do_stat },
1005 { "lstat ", do_lstat },
1006 { "fstat", do_fstat },
1007 { "chmod", do_chmod },
1008 { "chown", do_chown },
1009 { "readlink ", do_readlink },
1010 { "unlink", do_unlink },
1011 { "rename", do_rename },
1012 { "chdir ", do_chdir },
1013 { "lseek", do_lseek },
1014 { "rmdir", do_rmdir },
1015 { "symlink", do_symlink },
1016 { "mknod", do_mknod },
1017 { "mkdir", do_mkdir },
1018 { "link", do_link },
1019 { "gethome", do_gethome },
1020 { "getupdir", do_getupdir },
1021 { "login", do_login },
1022 { "quit", do_quit },
1023 { "utime", do_utime },
1026 static int ncommands = sizeof(commands)/sizeof(struct _command);
1028 static void exec_command (int command)
1030 if (command < 0 ||
1031 command >= ncommands ||
1032 commands [command].command == 0){
1033 fprintf (stderr, "Got unknown command: %d\n", command);
1034 DO_QUIT_VOID ();
1036 if (verbose) printf ("Command: %s\n", commands [command].command);
1037 (*commands [command].callback)();
1040 static void check_version (void)
1042 int version;
1044 rpc_get (msock, RPC_INT, &version, RPC_END);
1045 if (version >= 1 &&
1046 version <= RPC_PROGVER)
1047 rpc_send (msock, RPC_INT, MC_VERSION_OK, RPC_END);
1048 else
1049 rpc_send (msock, RPC_INT, MC_VERSION_MISMATCH, RPC_END);
1051 clnt_version = version;
1054 /* This routine is called by rpc_get/rpc_send when the connection is closed */
1055 void tcp_invalidate_socket (int sock)
1057 if (verbose) printf ("Connection closed\n");
1058 DO_QUIT_VOID();
1061 static void server (int sock)
1063 int command;
1065 msock = sock;
1066 quit_server = 0;
1068 check_version ();
1069 do {
1070 if (rpc_get (sock, RPC_INT, &command, RPC_END) &&
1071 (logged_in || command == MC_LOGIN))
1072 exec_command (command);
1073 } while (!quit_server);
1076 /* }}} */
1078 /* {{{ Net support code */
1080 static char *get_client (int portnum)
1082 int sock, clilen, newsocket;
1083 struct sockaddr_in client_address, server_address;
1084 struct hostent *hp;
1085 char hostname [255];
1086 int yes = 1;
1087 #ifdef __EMX__
1088 char *me;
1089 #endif
1091 if ((sock = socket (AF_INET, SOCK_STREAM, 0)) < 0)
1092 return "Cannot create socket";
1094 /* Use this to debug: */
1095 if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (char *) &yes, sizeof (yes)) < 0)
1096 return "setsockopt failed";
1098 gethostname (hostname, 255);
1099 if (verbose) printf ("hostname=%s\n", hostname);
1100 hp = gethostbyname (hostname);
1101 #ifdef __EMX__
1102 if (hp == 0 && (me = getenv("HOSTNAME")) && (0 == strcmp(hostname, me)))
1103 hp = gethostbyname ("localhost");
1104 #endif
1105 if (hp == 0)
1106 return "hp = 0!";
1108 memset ((char *) &server_address, 0, sizeof (server_address));
1109 server_address.sin_family = hp->h_addrtype;
1110 server_address.sin_addr.s_addr = htonl (INADDR_ANY);
1111 server_address.sin_port = htons (portnum);
1113 if (bind (sock, (struct sockaddr *) &server_address,
1114 sizeof (server_address)) < 0)
1115 return "Cannot bind";
1117 listen (sock, 5);
1119 for (;;){
1120 int child;
1122 clilen = sizeof (client_address);
1123 newsocket = accept (sock, (struct sockaddr *) &client_address,
1124 &clilen);
1126 if (isDaemon && (child = fork())) {
1127 int status;
1129 close (newsocket);
1130 waitpid (child, &status, 0);
1131 continue;
1134 if (isDaemon && fork()) exit (0);
1136 server (newsocket);
1137 close (newsocket);
1138 return 0;
1142 #ifdef HAVE_PMAP_SET
1143 static void signal_int_handler (int sig)
1145 pmap_unset (RPC_PROGNUM, RPC_PROGVER);
1147 #endif
1149 #ifndef IPPORT_RESERVED
1150 #define IPPORT_RESERVED 1024;
1151 #endif
1153 static int get_port_number (void)
1155 int port = 0;
1157 #ifdef HAVE_RRESVPORT
1158 int start_port = IPPORT_RESERVED;
1160 port = rresvport (&start_port);
1161 if (port == -1){
1162 if (geteuid () == 0){
1163 fprintf (stderr, "Could not bind the server on a reserved port\n");
1164 DO_QUIT_NONVOID (-1);
1166 port = 0;
1168 #endif
1169 if (port)
1170 return port;
1172 port = mcserver_port;
1174 return port;
1177 static void register_port (int portnum, int abort_if_fail)
1179 #ifdef HAVE_PMAP_SET
1180 /* Register our service with the portmapper */
1181 /* protocol: pmap_set (prognum, versnum, protocol, portp) */
1183 if (pmap_set (RPC_PROGNUM, RPC_PROGVER, IPPROTO_TCP, portnum))
1184 signal (SIGINT, signal_int_handler);
1185 else {
1186 fprintf (stderr, "Could not register service with portmapper\n");
1187 if (abort_if_fail)
1188 exit (1);
1190 #else
1191 if (abort_if_fail){
1192 fprintf (stderr,
1193 "This system lacks port registration, try using the -p\n"
1194 "flag to force installation at a given port");
1196 #endif
1199 /* }}} */
1201 int main (int argc, char *argv [])
1203 char *result;
1204 extern char *optarg;
1205 int c;
1207 while ((c = getopt (argc, argv, "fdiqp:v")) != -1){
1208 switch (c){
1209 case 'd':
1210 isDaemon = 1;
1211 verbose = 0;
1212 break;
1214 case 'v':
1215 verbose = 1;
1216 break;
1218 case 'f':
1219 ftp = 1;
1220 break;
1222 case 'q':
1223 verbose = 0;
1224 break;
1226 case 'p':
1227 portnum = atoi (optarg);
1228 break;
1230 case 'i':
1231 inetd_started = 1;
1232 break;
1234 case 'r':
1235 r_auth = 1;
1236 break;
1238 default:
1239 fprintf (stderr, "Usage is: mcserv [options] [-p portnum]\n\n"
1240 "options are:\n"
1241 "-d become a daemon (sets -q)\n"
1242 "-q quiet mode\n"
1243 /* "-r use rhost based authentication\n" */
1244 #ifndef HAVE_PAM
1245 "-f force ftp authentication\n"
1246 #endif
1247 "-v verbose mode\n"
1248 "-p to specify a port number to listen\n");
1249 exit (0);
1254 if (isDaemon && fork()) exit (0);
1256 if (portnum == 0)
1257 portnum = get_port_number ();
1259 if (portnum != -1) {
1260 register_port (portnum, 0);
1261 if (verbose)
1262 printf ("Using port %d\n", portnum);
1263 if ((result = get_client (portnum)))
1264 perror (result);
1265 #ifdef HAVE_PMAP_SET
1266 if (!isDaemon)
1267 pmap_unset (RPC_PROGNUM, RPC_PROGVER);
1268 #endif
1270 exit (return_code);
1273 /* FIXME: This function should not be used in mcserv */
1274 void vfs_die( char *m )
1276 fputs (m, stderr);
1277 exit (1);