Added cs to the list of languages
[midnight-commander.git] / vfs / mcserv.c
blobee5db004024475f6958be083a52d6976ec1c229a
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., 675 Mass Ave, Cambridge, MA 02139, 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_SHADOW_H
55 # include <shadow.h>
56 #else
57 # ifdef HAVE_SHADOW_SHADOW_H
58 # include <shadow/shadow.h>
59 # endif
60 #endif
61 #ifdef HAVE_CRYPT_H
62 # include <crypt.h>
63 #endif
64 #include <sys/types.h>
65 #include <sys/stat.h>
66 #include <errno.h>
67 #include <signal.h>
68 #ifdef SCO_FLAVOR
69 # include <sys/timeb.h> /* alex: for struct timeb definition */
70 #endif /* SCO_FLAVOR */
71 #include <time.h>
72 #include <utime.h>
74 /* Network include files */
75 #include <sys/socket.h>
76 #include <netinet/in.h>
77 #include <netdb.h>
78 #include <arpa/inet.h>
79 #ifdef HAVE_PMAP_SET
80 # include <rpc/rpc.h>
81 # include <rpc/pmap_prot.h>
82 # ifdef HAVE_RPC_PMAP_CLNT_H
83 # include <rpc/pmap_clnt.h>
84 # endif
85 #endif
87 /* Authentication include files */
88 #include <pwd.h>
89 #ifdef HAVE_PAM
90 # include <security/pam_misc.h>
91 # ifndef PAM_ESTABLISH_CRED
92 # define PAM_ESTABLISH_CRED PAM_CRED_ESTABLISH
93 # endif
94 #endif
96 #include "utilvfs.h"
98 #include "vfs.h"
99 #include "mcfs.h"
100 #include "tcputil.h"
102 /* The socket from which we accept commands */
103 int msock;
105 /* Requested version number from client */
106 static int clnt_version;
108 /* If non zero, we accept further commands */
109 int logged_in = 0;
111 /* Home directory */
112 char *home_dir = NULL;
114 char *up_dir = NULL;
116 /* Were we started from inetd? */
117 int inetd_started = 0;
119 /* Are we running as a daemon? */
120 int isDaemon = 0;
122 /* guess */
123 int verbose = 0;
125 /* ftp auth */
126 int ftp = 0;
128 /* port number in which we listen to connections,
129 * if zero, we try to contact the portmapper to get a port, and
130 * if it's not possible, then we use a hardcoded value
132 int portnum = 0;
134 /* if the server will use rcmd based authentication (hosts.equiv .rhosts) */
135 int r_auth = 0;
137 #define OPENDIR_HANDLES 8
139 #define DO_QUIT_VOID() \
140 do { \
141 quit_server = 1; \
142 return_code = 1; \
143 return; \
144 } while (0)
146 /* Only used by get_port_number */
147 #define DO_QUIT_NONVOID(a) \
148 do { \
149 quit_server = 1; \
150 return_code = 1; \
151 return (a); \
152 } while (0)
154 char buffer [4096];
155 int debug = 1;
156 static int quit_server;
157 static int return_code;
159 /* }}} */
161 /* {{{ Misc routines */
163 void send_status (int status, int errno_number)
165 rpc_send (msock, RPC_INT, status, RPC_INT, errno_number, RPC_END);
166 errno = 0;
169 /* }}} */
171 /* {{{ File with handle operations */
173 void do_open (void)
175 int handle, flags, mode;
176 char *arg;
178 rpc_get (msock, RPC_STRING, &arg, RPC_INT, &flags, RPC_INT, &mode,RPC_END);
180 handle = open (arg, flags, mode);
181 send_status (handle, errno);
182 g_free (arg);
185 void do_read (void)
187 int handle, count, n;
188 void *data;
190 rpc_get (msock, RPC_INT, &handle, RPC_INT, &count, RPC_END);
191 data = g_malloc (count);
192 if (!data){
193 send_status (-1, ENOMEM);
194 return;
196 if (verbose) printf ("count=%d\n", count);
197 n = read (handle, data, count);
198 if (verbose) printf ("result=%d\n", n);
199 if (n < 0){
200 send_status (-1, errno);
201 return;
203 send_status (n, 0);
204 rpc_send (msock, RPC_BLOCK, n, data, RPC_END);
206 g_free (data);
209 void do_write (void)
211 int handle, count, status;
212 char buffer [8192];
214 rpc_get (msock, RPC_INT, &handle, RPC_INT, &count, RPC_END);
215 status = 0;
216 while (count){
217 int nbytes = count > 8192 ? 8192 : count;
219 rpc_get (msock, RPC_BLOCK, nbytes, buffer, RPC_END);
220 status = write (handle, buffer, nbytes);
221 count -= nbytes;
223 send_status (status, errno);
226 void do_lseek (void)
228 int handle, offset, whence, status;
230 rpc_get (msock,
231 RPC_INT, &handle,
232 RPC_INT, &offset,
233 RPC_INT, &whence, RPC_END);
234 status = lseek (handle, offset, whence);
235 send_status (status, errno);
238 void do_close (void)
240 int handle, status;
242 rpc_get (msock, RPC_INT, &handle, RPC_END);
243 status = close (handle);
244 send_status (status, errno);
247 /* }}} */
249 /* {{{ Stat family routines */
251 void send_time (int sock, time_t time)
253 if (clnt_version == 1) {
254 char *ct;
255 int month;
257 ct = ctime (&time);
258 ct [3] = ct [10] = ct [13] = ct [16] = ct [19] = 0;
260 /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
261 if (ct [4] == 'J'){
262 if (ct [5] == 'a'){
263 month = 0;
264 } else
265 month = (ct [6] == 'n') ? 5 : 6;
266 } else if (ct [4] == 'F'){
267 month = 1;
268 } else if (ct [4] == 'M'){
269 month = (ct [6] == 'r') ? 2 : 5;
270 } else if (ct [4] == 'A'){
271 month = (ct [5] == 'p') ? 3 : 7;
272 } else if (ct [4] == 'S'){
273 month = 8;
274 } else if (ct [4] == 'O'){
275 month = 9;
276 } else if (ct [4] == 'N'){
277 month = 10;
278 } else
279 month = 11;
280 rpc_send (msock,
281 RPC_INT, atoi (&ct [17]), /* sec */
282 RPC_INT, atoi (&ct [14]), /* min */
283 RPC_INT, atoi (&ct [11]), /* hour */
284 RPC_INT, atoi (&ct [8]), /* mday */
285 RPC_INT, atoi (&ct [20]), /* year */
286 RPC_INT, month, /* month */
287 RPC_END);
288 } else {
289 long ltime = (long) time;
290 char buf[BUF_SMALL];
292 g_snprintf (buf, sizeof(buf), "%lx", ltime);
293 rpc_send (msock,
294 RPC_STRING, buf,
295 RPC_END);
299 void send_stat_info (struct stat *st)
301 int mylong;
302 int blocks =
303 #ifdef HAVE_ST_BLOCKS
304 st->st_blocks;
305 #else
306 st->st_size / 1024;
307 #endif
309 mylong = st->st_dev;
310 rpc_send (msock, RPC_INT, (long) st->st_dev,
311 RPC_INT, (long) st->st_ino,
312 RPC_INT, (long) st->st_mode,
313 RPC_INT, (long) st->st_nlink,
314 RPC_INT, (long) st->st_uid,
315 RPC_INT, (long) st->st_gid,
316 RPC_INT, (long) st->st_size,
317 RPC_INT, (long) blocks, RPC_END);
318 send_time (msock, st->st_atime);
319 send_time (msock, st->st_mtime);
320 send_time (msock, st->st_ctime);
323 void do_lstat ()
325 struct stat st;
326 char *file;
327 int n;
329 rpc_get (msock, RPC_STRING, &file, RPC_END);
330 n = lstat (file, &st);
331 send_status (n, errno);
332 if (n >= 0)
333 send_stat_info (&st);
334 g_free (file);
337 void do_fstat (void)
339 int handle;
340 int n;
341 struct stat st;
343 rpc_get (msock, RPC_INT, &handle, RPC_END);
344 n = fstat (handle, &st);
345 send_status (n, errno);
346 if (n < 0)
347 return;
349 send_stat_info (&st);
352 void do_stat ()
354 struct stat st;
355 int n;
356 char *file;
358 rpc_get (msock, RPC_STRING, &file, RPC_END);
360 n = stat (file, &st);
361 send_status (n, errno);
362 if (n >= 0)
363 send_stat_info (&st);
364 g_free (file);
367 /* }}} */
369 /* {{{ Directory lookup operations */
371 static struct {
372 int used;
373 DIR *dirs [OPENDIR_HANDLES];
374 char *names [OPENDIR_HANDLES];
375 } mcfs_DIR;
377 void close_handle (int handle)
379 if (mcfs_DIR.used > 0) mcfs_DIR.used--;
380 if (mcfs_DIR.dirs [handle])
381 closedir (mcfs_DIR.dirs [handle]);
382 if (mcfs_DIR.names [handle])
383 g_free (mcfs_DIR.names [handle]);
384 mcfs_DIR.dirs [handle] = 0;
385 mcfs_DIR.names [handle] = 0;
388 void do_opendir (void)
390 int handle, i;
391 char *arg;
392 DIR *p;
394 rpc_get (msock, RPC_STRING, &arg, RPC_END);
396 if (mcfs_DIR.used == OPENDIR_HANDLES){
397 send_status (-1, ENFILE); /* Error */
398 g_free (arg);
399 return;
402 handle = -1;
403 for (i = 0; i < OPENDIR_HANDLES; i++){
404 if (mcfs_DIR.dirs [i] == 0){
405 handle = i;
406 break;
410 if (handle == -1){
411 send_status (-1, EMFILE);
412 g_free (arg);
413 if (!inetd_started)
414 fprintf (stderr, "OOPS! you have found a bug in mc - do_opendir()!\n");
415 return;
418 if (verbose) printf ("handle=%d\n", handle);
419 p = opendir (arg);
420 if (p){
421 mcfs_DIR.dirs [handle] = p;
422 mcfs_DIR.names [handle] = arg;
423 mcfs_DIR.used ++;
425 /* Because 0 is an error value */
426 rpc_send (msock, RPC_INT, handle+1, RPC_INT, 0, RPC_END);
428 } else {
429 send_status (-1, errno);
430 g_free (arg);
434 /* Sends the complete directory listing, as well as the stat information */
435 void do_readdir (void)
437 struct dirent *dirent;
438 struct stat st;
439 int handle, n;
440 char *fname = 0;
442 rpc_get (msock, RPC_INT, &handle, RPC_END);
444 if (!handle){
445 rpc_send (msock, RPC_INT, 0, RPC_END);
446 return;
449 /* We incremented it in opendir */
450 handle --;
452 while ((dirent = readdir (mcfs_DIR.dirs [handle]))){
453 int length = NLENGTH (dirent);
455 rpc_send (msock, RPC_INT, length, RPC_END);
456 rpc_send (msock, RPC_BLOCK, length, dirent->d_name, RPC_END);
457 fname = g_strconcat (mcfs_DIR.names [handle],
458 PATH_SEP_STR, dirent->d_name, NULL);
459 n = lstat (fname, &st);
460 send_status (n, errno);
461 g_free (fname);
462 if (n >= 0)
463 send_stat_info (&st);
465 rpc_send (msock, RPC_INT, 0, RPC_END);
468 void do_closedir (void)
470 int handle;
472 rpc_get (msock, RPC_INT, &handle, RPC_END);
473 close_handle (handle-1);
476 /* }}} */
478 /* {{{ Operations with one and two file name argument */
480 void do_chdir (void)
482 char *file;
483 int status;
485 rpc_get (msock, RPC_STRING, &file, RPC_END);
487 status = chdir (file);
488 send_status (status, errno);
489 g_free (file);
492 void do_rmdir (void)
494 char *file;
495 int status;
497 rpc_get (msock, RPC_STRING, &file, RPC_END);
499 status = rmdir (file);
500 send_status (status, errno);
501 g_free (file);
504 void do_mkdir (void)
506 char *file;
507 int mode, status;
509 rpc_get (msock, RPC_STRING, &file, RPC_INT, &mode, RPC_END);
511 status = mkdir (file, mode);
512 send_status (status, errno);
513 g_free (file);
516 void do_mknod (void)
518 char *file;
519 int mode, dev, status;
521 rpc_get (msock, RPC_STRING, &file, RPC_INT, &mode, RPC_INT, &dev, RPC_END);
523 status = mknod (file, mode, dev);
524 send_status (status, errno);
525 g_free (file);
528 void do_readlink (void)
530 char buffer [2048];
531 char *file;
532 int n;
534 rpc_get (msock, RPC_STRING, &file, RPC_END);
535 n = readlink (file, buffer, 2048);
536 send_status (n, errno);
537 if (n >= 0) {
538 buffer [n] = 0;
539 rpc_send (msock, RPC_STRING, buffer, RPC_END);
541 g_free (file);
544 void do_unlink (void)
546 char *file;
547 int status;
549 rpc_get (msock, RPC_STRING, &file, RPC_END);
550 status = unlink (file);
551 send_status (status, errno);
552 g_free (file);
555 void do_rename (void)
557 char *f1, *f2;
558 int status;
560 rpc_get (msock, RPC_STRING, &f1, RPC_STRING, &f2, RPC_END);
561 status = rename (f1, f2);
562 send_status (status, errno);
563 g_free (f1); g_free (f2);
566 void do_symlink (void)
568 char *f1, *f2;
569 int status;
571 rpc_get (msock, RPC_STRING, &f1, RPC_STRING, &f2, RPC_END);
572 status = symlink (f1, f2);
573 send_status (status, errno);
574 g_free (f1); g_free (f2);
577 void do_link (void)
579 char *f1, *f2;
580 int status;
582 rpc_get (msock, RPC_STRING, &f1, RPC_STRING, &f2, RPC_END);
583 status = link (f1, f2);
584 send_status (status, errno);
585 g_free (f1); g_free (f2);
589 /* }}} */
591 /* {{{ Misc commands */
593 void do_gethome (void)
595 rpc_send (msock, RPC_STRING, (home_dir) ? home_dir : "/", RPC_END);
598 void do_getupdir (void)
600 rpc_send (msock, RPC_STRING, (up_dir) ? up_dir : "/", RPC_END);
603 void do_chmod (void)
605 char *file;
606 int mode, status;
608 rpc_get (msock, RPC_STRING, &file, RPC_INT, &mode, RPC_END);
609 status = chmod (file, mode);
610 send_status (status, errno);
611 g_free (file);
614 void do_chown (void)
616 char *file;
617 int owner, group, status;
619 rpc_get (msock, RPC_STRING, &file,RPC_INT, &owner, RPC_INT,&group,RPC_END);
620 status = chown (file, owner, group);
621 send_status (status, errno);
622 g_free (file);
625 void do_utime (void)
627 char *file;
628 int status;
629 long atime;
630 long mtime;
631 char *as;
632 char *ms;
633 struct utimbuf times;
635 rpc_get (msock, RPC_STRING, &file,
636 RPC_STRING, &as,
637 RPC_STRING, &ms,
638 RPC_END);
639 sscanf (as, "%lx", &atime);
640 sscanf (ms, "%lx", &mtime);
641 if (verbose) printf ("Got a = %s, m = %s, comp a = %ld, m = %ld\n",
642 as, ms, atime, mtime);
643 g_free (as);
644 g_free (ms);
645 times.actime = (time_t) atime;
646 times.modtime = (time_t) mtime;
647 status = utime (file, &times);
648 send_status (status, errno);
649 g_free (file);
652 void do_quit ()
654 quit_server = 1;
657 #ifdef HAVE_PAM
659 struct user_pass {
660 char *username;
661 char *password;
665 mc_pam_conversation (int messages, const struct pam_message **msg,
666 struct pam_response **resp, void *appdata_ptr)
668 struct pam_response *r;
669 struct user_pass *up = appdata_ptr;
670 int status;
672 r = g_new (struct pam_response, messages);
673 if (!r)
674 return PAM_CONV_ERR;
675 *resp = r;
677 for (status = PAM_SUCCESS; messages--; msg++, r++){
678 switch ((*msg)->msg_style){
680 case PAM_PROMPT_ECHO_ON:
681 r->resp = g_strdup (up->username);
682 r->resp_retcode = PAM_SUCCESS;
683 break;
685 case PAM_PROMPT_ECHO_OFF:
686 r->resp = g_strdup (up->password);
687 r->resp_retcode = PAM_SUCCESS;
688 break;
690 case PAM_ERROR_MSG:
691 r->resp = NULL;
692 r->resp_retcode = PAM_SUCCESS;
693 break;
695 case PAM_TEXT_INFO:
696 r->resp = NULL;
697 r->resp_retcode = PAM_SUCCESS;
698 break;
701 return status;
704 static struct pam_conv conv = { &mc_pam_conversation, NULL };
707 /* Return 0 if authentication failed, 1 otherwise */
709 mc_pam_auth (char *username, char *password)
711 pam_handle_t *pamh;
712 struct user_pass up;
713 int status;
715 up.username = username;
716 up.password = password;
717 conv.appdata_ptr = &up;
719 if ((status = pam_start("mcserv", username, &conv, &pamh)) != PAM_SUCCESS)
720 goto failed_pam;
721 if ((status = pam_authenticate (pamh, 0)) != PAM_SUCCESS)
722 goto failed_pam;
723 if ((status = pam_acct_mgmt (pamh, 0)) != PAM_SUCCESS)
724 goto failed_pam;
725 if ((status = pam_setcred (pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS)
726 goto failed_pam;
727 pam_end (pamh, status);
728 return 0;
730 failed_pam:
731 pam_end (pamh, status);
732 return 1;
735 #else /* Code for non-PAM authentication */
737 /* Keep reading until we find a \n */
738 static int next_line (int socket)
740 char c;
742 while (1){
743 if (read (socket, &c, 1) <= 0)
744 return 0;
745 if (c == '\n')
746 return 1;
750 static int ftp_answer (int sock, char *text)
752 char answer [4];
754 next_line (sock);
755 socket_read_block (sock, answer, 3);
756 answer [3] = 0;
757 if (strcmp (answer, text) == 0)
758 return 1;
759 return 0;
762 int do_ftp_auth (char *username, char *password)
764 struct sockaddr_in local_address;
765 unsigned long inaddr;
766 int my_socket;
767 char answer [4];
769 bzero ((char *) &local_address, sizeof (local_address));
771 local_address.sin_family = AF_INET;
772 /* FIXME: extract the ftp port with the proper function */
773 local_address.sin_port = htons (21);
775 /* Convert localhost to usable format */
776 if ((inaddr = inet_addr ("127.0.0.1")) != -1)
777 bcopy ((char *) &inaddr, (char *) &local_address.sin_addr,
778 sizeof (inaddr));
780 if ((my_socket = socket (AF_INET, SOCK_STREAM, 0)) < 0){
781 if (!isDaemon) fprintf (stderr, "do_auth: can't create socket\n");
782 return 0;
784 if (connect (my_socket, (struct sockaddr *) &local_address,
785 sizeof (local_address)) < 0){
786 fprintf (stderr,
787 "do_auth: can't connect to ftp daemon for authentication\n");
788 close (my_socket);
789 return 0;
791 send_string (my_socket, "user ");
792 send_string (my_socket, username);
793 send_string (my_socket, "\r\n");
794 if (!ftp_answer (my_socket, "331")){
795 send_string (my_socket, "quit\r\n");
796 close (my_socket);
797 return 0;
799 next_line (my_socket); /* Eat all the line */
800 send_string (my_socket, "pass ");
801 send_string (my_socket, password);
802 send_string (my_socket, "\r\n");
803 socket_read_block (my_socket, answer, 3);
804 answer [3] = 0;
805 send_string (my_socket, "\r\n");
806 send_string (my_socket, "quit\r\n");
807 close (my_socket);
808 if (strcmp (answer, "230") == 0)
809 return 1;
810 return 0;
813 int do_classic_auth (char *username, char *password)
815 struct passwd *this;
816 int ret;
817 #ifdef LINUX_SHADOW
818 struct spwd *spw;
819 extern char *pw_encrypt (char *, char *);
820 #else
821 #ifdef NEED_CRYPT_PROTOTYPE
822 extern char *crypt (const char *, const char *);
823 #endif
824 #endif
826 if ((this = getpwnam (username)) == 0)
827 return 0;
829 #ifdef LINUX_SHADOW
830 if ((spw = getspnam (username)) == NULL)
831 this->pw_passwd = "*";
832 else
833 this->pw_passwd = spw->sp_pwdp;
834 if (strcmp (pw_encrypt (password, this->pw_passwd), this->pw_passwd) == 0)
835 ret = 1;
836 else
837 ret = 0;
838 #else
839 #ifdef HAVE_CRYPT
840 if (strcmp (crypt (password, this->pw_passwd), this->pw_passwd) == 0){
841 ret = 1;
842 } else
843 #endif
845 ret = 0;
847 #endif
848 endpwent ();
849 return ret;
851 #endif /* non-PAM authentication */
853 /* Try to authenticate the user based on:
854 - PAM if the system has it, else it checks:
855 - pwdauth if the system supports it.
856 - conventional auth (check salt on /etc/passwd, crypt, and compare
857 - try to contact the local ftp server and login (if -f flag used)
860 do_auth (char *username, char *password)
862 int auth = 0;
863 struct passwd *this;
865 if (strcmp (username, "anonymous") == 0)
866 username = "ftp";
868 #ifdef HAVE_PAM
869 if (mc_pam_auth (username, password) == 0)
870 auth = 1;
871 #else /* if there is no pam */
872 #ifdef HAVE_PWDAUTH
873 if (pwdauth (username, password) == 0)
874 auth = 1;
875 else
876 #endif
877 if (do_classic_auth (username, password))
878 auth = 1;
879 else if (ftp)
880 auth = do_ftp_auth (username, password);
881 #endif /* not pam */
883 if (!auth)
884 return 0;
886 this = getpwnam (username);
887 if (this == 0)
888 return 0;
890 if (chdir (this->pw_dir) == -1)
891 return 0;
893 if (this->pw_dir [strlen (this->pw_dir) - 1] == '/')
894 home_dir = g_strdup (this->pw_dir);
895 else {
896 home_dir = g_malloc (strlen (this->pw_dir) + 2);
897 if (home_dir) {
898 strcpy (home_dir, this->pw_dir);
899 strcat (home_dir, "/");
900 } else
901 home_dir = "/";
905 if (setgid (this->pw_gid) == -1)
906 return 0;
908 #ifdef HAVE_INITGROUPS
909 #ifdef NGROUPS_MAX
910 if (NGROUPS_MAX > 1 && initgroups (this->pw_name, this->pw_gid))
911 return 0;
912 #endif
913 #endif
915 #if defined (HAVE_SETUID)
916 if (setuid (this->pw_uid))
917 return 0;
918 #elif defined (HAVE_SETREUID)
919 if (setreuid (this->pw_uid, this->pw_uid))
920 return 0;
921 #endif
923 /* If the setuid call failed, then deny access */
924 /* This should fix the problem on those machines with strange setups */
925 if (getuid () != this->pw_uid)
926 return 0;
928 if (strcmp (username, "ftp") == 0)
929 chroot (this->pw_dir);
931 endpwent ();
932 return auth;
935 #if 0
936 int do_rauth (int socket)
938 struct sockaddr_in from;
939 struct hostent *hp;
941 if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0)
942 return 0;
943 from.sin_port = ntohs ((unsigned short) from.sin_port);
945 /* Strange, this should not happend */
946 if (from.sin_family != AF_INET)
947 return 0;
949 hp = gethostbyaddr((char *)&fromp.sin_addr, sizeof (struct in_addr),
950 fromp.sin_family);
953 #endif
955 int do_rauth (int msock)
957 return 0;
960 void login_reply (int logged_in)
962 rpc_send (msock, RPC_INT,
963 logged_in ? MC_LOGINOK : MC_INVALID_PASS,
964 RPC_END);
967 /* FIXME: Implement the anonymous login */
968 void do_login ()
970 char *username;
971 char *password;
972 int result;
974 rpc_get (msock, RPC_LIMITED_STRING, &up_dir, RPC_LIMITED_STRING, &username, RPC_END);
975 if (verbose) printf ("username: %s\n", username);
977 if (r_auth){
978 logged_in = do_rauth (msock);
979 if (logged_in){
980 login_reply (logged_in);
981 return;
984 rpc_send (msock, RPC_INT, MC_NEED_PASSWORD, RPC_END);
985 rpc_get (msock, RPC_INT, &result, RPC_END);
986 if (result == MC_QUIT)
987 DO_QUIT_VOID ();
988 if (result != MC_PASS){
989 if (verbose) printf ("do_login: Unknown response: %d\n", result);
990 DO_QUIT_VOID ();
992 rpc_get (msock, RPC_LIMITED_STRING, &password, RPC_END);
993 logged_in = do_auth (username, password);
994 endpwent ();
995 login_reply (logged_in);
998 /* }}} */
1000 /* {{{ Server and dispatching functions */
1002 /* This structure must be kept in synch with mcfs.h enums */
1004 struct _command {
1005 char *command;
1006 void (*callback)(void);
1007 } commands [] = {
1008 { "open", do_open },
1009 { "close", do_close },
1010 { "read", do_read },
1011 { "write", do_write },
1012 { "opendir", do_opendir },
1013 { "readdir", do_readdir },
1014 { "closedir", do_closedir },
1015 { "stat ", do_stat },
1016 { "lstat ", do_lstat },
1017 { "fstat", do_fstat },
1018 { "chmod", do_chmod },
1019 { "chown", do_chown },
1020 { "readlink ", do_readlink },
1021 { "unlink", do_unlink },
1022 { "rename", do_rename },
1023 { "chdir ", do_chdir },
1024 { "lseek", do_lseek },
1025 { "rmdir", do_rmdir },
1026 { "symlink", do_symlink },
1027 { "mknod", do_mknod },
1028 { "mkdir", do_mkdir },
1029 { "link", do_link },
1030 { "gethome", do_gethome },
1031 { "getupdir", do_getupdir },
1032 { "login", do_login },
1033 { "quit", do_quit },
1034 { "utime", do_utime },
1037 static int ncommands = sizeof(commands)/sizeof(struct _command);
1039 void exec_command (int command)
1041 if (command < 0 ||
1042 command >= ncommands ||
1043 commands [command].command == 0){
1044 fprintf (stderr, "Got unknown command: %d\n", command);
1045 DO_QUIT_VOID ();
1047 if (verbose) printf ("Command: %s\n", commands [command].command);
1048 (*commands [command].callback)();
1051 void check_version ()
1053 int version;
1055 rpc_get (msock, RPC_INT, &version, RPC_END);
1056 if (version >= 1 &&
1057 version <= RPC_PROGVER)
1058 rpc_send (msock, RPC_INT, MC_VERSION_OK, RPC_END);
1059 else
1060 rpc_send (msock, RPC_INT, MC_VERSION_MISMATCH, RPC_END);
1062 clnt_version = version;
1065 /* This routine is called by rpc_get/rpc_send when the connection is closed */
1066 void tcp_invalidate_socket (int sock)
1068 if (verbose) printf ("Connection closed\n");
1069 DO_QUIT_VOID();
1072 void server (int sock)
1074 int command;
1076 msock = sock;
1077 quit_server = 0;
1079 check_version ();
1080 do {
1081 if (rpc_get (sock, RPC_INT, &command, RPC_END) &&
1082 (logged_in || command == MC_LOGIN))
1083 exec_command (command);
1084 } while (!quit_server);
1087 /* }}} */
1089 /* {{{ Net support code */
1091 char *get_client (int portnum)
1093 int sock, clilen, newsocket;
1094 struct sockaddr_in client_address, server_address;
1095 struct hostent *hp;
1096 char hostname [255];
1097 int yes = 1;
1099 if ((sock = socket (AF_INET, SOCK_STREAM, 0)) < 0)
1100 return "Can't create socket";
1102 /* Use this to debug: */
1103 if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (char *) &yes, sizeof (yes)) < 0)
1104 return "setsockopt failed";
1106 gethostname (hostname, 255);
1107 if (verbose) printf ("hostname=%s\n", hostname);
1108 hp = gethostbyname (hostname);
1109 if (hp == 0)
1110 return "hp = 0!";
1112 bzero ((char *) &server_address, sizeof (server_address));
1113 server_address.sin_family = hp->h_addrtype;
1114 server_address.sin_addr.s_addr = htonl (INADDR_ANY);
1115 server_address.sin_port = htons (portnum);
1117 if (bind (sock, (struct sockaddr *) &server_address,
1118 sizeof (server_address)) < 0)
1119 return "Can't bind";
1121 listen (sock, 5);
1123 for (;;){
1124 int child;
1126 clilen = sizeof (client_address);
1127 newsocket = accept (sock, (struct sockaddr *) &client_address,
1128 &clilen);
1130 if (isDaemon && (child = fork())) {
1131 int status;
1133 close (newsocket);
1134 waitpid (child, &status, 0);
1135 continue;
1138 if (isDaemon && fork()) exit (0);
1140 server (newsocket);
1141 close (newsocket);
1142 return 0;
1146 #ifdef HAVE_PMAP_SET
1147 void signal_int_handler (int sig)
1149 pmap_unset (RPC_PROGNUM, RPC_PROGVER);
1151 #endif
1153 #ifndef IPPORT_RESERVED
1154 #define IPPORT_RESERVED 1024;
1155 #endif
1157 int get_port_number ()
1159 int port = 0;
1161 #ifdef HAVE_RRESVPORT
1162 int start_port = IPPORT_RESERVED;
1164 port = rresvport (&start_port);
1165 if (port == -1){
1166 if (geteuid () == 0){
1167 fprintf (stderr, "Could not bind the server on a reserved port\n");
1168 DO_QUIT_NONVOID (-1);
1170 port = 0;
1172 #endif
1173 if (port)
1174 return port;
1176 port = mcserver_port;
1178 return port;
1181 void register_port (int portnum, int abort_if_fail)
1183 #ifdef HAVE_PMAP_SET
1184 /* Register our service with the portmapper */
1185 /* protocol: pmap_set (prognum, versnum, protocol, portp) */
1187 if (pmap_set (RPC_PROGNUM, RPC_PROGVER, IPPROTO_TCP, portnum))
1188 signal (SIGINT, signal_int_handler);
1189 else {
1190 fprintf (stderr, "Could not register service with portmapper\n");
1191 if (abort_if_fail)
1192 exit (1);
1194 #else
1195 if (abort_if_fail){
1196 fprintf (stderr,
1197 "This system lacks port registration, try using the -p\n"
1198 "flag to force installation at a given port");
1200 #endif
1203 /* }}} */
1205 int main (int argc, char *argv [])
1207 char *result;
1208 extern char *optarg;
1209 int c;
1211 while ((c = getopt (argc, argv, "fdiqp:v")) != -1){
1212 switch (c){
1213 case 'd':
1214 isDaemon = 1;
1215 verbose = 0;
1216 break;
1218 case 'v':
1219 verbose = 1;
1220 break;
1222 case 'f':
1223 ftp = 1;
1224 break;
1226 case 'q':
1227 verbose = 0;
1228 break;
1230 case 'p':
1231 portnum = atoi (optarg);
1232 break;
1234 case 'i':
1235 inetd_started = 1;
1236 break;
1238 case 'r':
1239 r_auth = 1;
1240 break;
1242 default:
1243 fprintf (stderr, "Usage is: mcserv [options] [-p portnum]\n\n"
1244 "options are:\n"
1245 "-d become a daemon (sets -q)\n"
1246 "-q quiet mode\n"
1247 /* "-r use rhost based authentication\n" */
1248 #ifndef HAVE_PAM
1249 "-f force ftp authentication\n"
1250 #endif
1251 "-v verbose mode\n"
1252 "-p to specify a port number to listen\n");
1253 exit (0);
1258 if (isDaemon && fork()) exit (0);
1260 if (portnum == 0)
1261 portnum = get_port_number ();
1263 if (portnum != -1) {
1264 register_port (portnum, 0);
1265 if (verbose)
1266 printf ("Using port %d\n", portnum);
1267 if ((result = get_client (portnum)))
1268 perror (result);
1269 #ifdef HAVE_PMAP_SET
1270 if (!isDaemon)
1271 pmap_unset (RPC_PROGNUM, RPC_PROGVER);
1272 #endif
1274 exit (return_code);
1277 /* This functions are not used */
1278 void message (int is_error, char *text, char *msg)
1280 printf ("%s %s\n", text, msg);
1283 char *unix_error_string (int a)
1285 return "none";
1288 void vfs_die( char *m )
1290 fprintf (stderr, m);
1291 exit (1);
1293 #ifdef HAVE_MAD
1294 char * mad_strconcat (const char *first, ...)
1296 va_list ap;
1297 long len;
1298 char *data, *result;
1300 if (!first)
1301 return 0;
1303 len = strlen (first) + 1;
1304 va_start (ap, first);
1306 while ((data = va_arg (ap, char *)) != 0)
1307 len += strlen (data);
1309 result = g_malloc (len);
1311 va_end (ap);
1313 va_start (ap, first);
1314 strcpy (result, first);
1316 while ((data = va_arg (ap, char *)) != 0)
1317 strcat (result, data);
1319 va_end (ap);
1321 return result;
1323 #endif /* HAVE_MAD */