1 /* Server for the Midnight Commander Virtual File System.
3 Copyright (C) 1995, 1996, 1997 The Free Software Foundation
6 Miguel de Icaza, 1995, 1997,
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.
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
28 We should use syslog to register login/logout.
32 /* {{{ Includes and global variables */
46 # include <sys/param.h>
48 # define NGROUPS_MAX NGROUPS
57 # ifdef HAVE_SHADOW_SHADOW_H
58 # include <shadow/shadow.h>
64 #include <sys/types.h>
70 /* Network include files */
71 #include <sys/socket.h>
72 #include <netinet/in.h>
74 #include <arpa/inet.h>
77 # include <rpc/pmap_prot.h>
78 # ifdef HAVE_RPC_PMAP_CLNT_H
79 # include <rpc/pmap_clnt.h>
83 /* Authentication include files */
86 # include <security/pam_misc.h>
87 # ifndef PAM_ESTABLISH_CRED
88 # define PAM_ESTABLISH_CRED PAM_CRED_ESTABLISH
98 /* The socket from which we accept commands */
101 /* Requested version number from client */
102 static int clnt_version
;
104 /* If non zero, we accept further commands */
108 char *home_dir
= NULL
;
112 /* Were we started from inetd? */
113 int inetd_started
= 0;
115 /* Are we running as a daemon? */
124 /* port number in which we listen to connections,
125 * if zero, we try to contact the portmapper to get a port, and
126 * if it's not possible, then we use a hardcoded value
130 /* if the server will use rcmd based authentication (hosts.equiv .rhosts) */
133 #define OPENDIR_HANDLES 8
135 #define DO_QUIT_VOID() \
142 /* Only used by get_port_number */
143 #define DO_QUIT_NONVOID(a) \
152 static int quit_server
;
153 static int return_code
;
157 /* {{{ Misc routines */
159 static void send_status (int status
, int errno_number
)
161 rpc_send (msock
, RPC_INT
, status
, RPC_INT
, errno_number
, RPC_END
);
167 /* {{{ File with handle operations */
169 static void do_open (void)
171 int handle
, flags
, mode
;
174 rpc_get (msock
, RPC_STRING
, &arg
, RPC_INT
, &flags
, RPC_INT
, &mode
,RPC_END
);
176 handle
= open (arg
, flags
, mode
);
177 send_status (handle
, errno
);
181 static void do_read (void)
183 int handle
, count
, n
;
186 rpc_get (msock
, RPC_INT
, &handle
, RPC_INT
, &count
, RPC_END
);
187 data
= g_malloc (count
);
189 send_status (-1, ENOMEM
);
192 if (verbose
) printf ("count=%d\n", count
);
193 n
= read (handle
, data
, count
);
194 if (verbose
) printf ("result=%d\n", n
);
196 send_status (-1, errno
);
200 rpc_send (msock
, RPC_BLOCK
, n
, data
, RPC_END
);
205 static void do_write (void)
207 int handle
, count
, status
, written
= 0;
210 rpc_get (msock
, RPC_INT
, &handle
, RPC_INT
, &count
, RPC_END
);
213 int nbytes
= count
> 8192 ? 8192 : count
;
215 rpc_get (msock
, RPC_BLOCK
, nbytes
, buf
, RPC_END
);
216 status
= write (handle
, buf
, nbytes
);
218 send_status (status
, errno
);
221 /* FIXED: amount written must be returned to caller */
223 if (status
< nbytes
) {
224 send_status (written
, errno
);
229 send_status (written
, errno
);
232 static void do_lseek (void)
234 int handle
, offset
, whence
, status
;
239 RPC_INT
, &whence
, RPC_END
);
240 status
= lseek (handle
, offset
, whence
);
241 send_status (status
, errno
);
244 static void do_close (void)
248 rpc_get (msock
, RPC_INT
, &handle
, RPC_END
);
249 status
= close (handle
);
250 send_status (status
, errno
);
255 /* {{{ Stat family routines */
257 static void send_time (int sock
, time_t time
)
259 if (clnt_version
== 1) {
264 ct
[3] = ct
[10] = ct
[13] = ct
[16] = ct
[19] = 0;
266 /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
271 month
= (ct
[6] == 'n') ? 5 : 6;
272 } else if (ct
[4] == 'F'){
274 } else if (ct
[4] == 'M'){
275 month
= (ct
[6] == 'r') ? 2 : 5;
276 } else if (ct
[4] == 'A'){
277 month
= (ct
[5] == 'p') ? 3 : 7;
278 } else if (ct
[4] == 'S'){
280 } else if (ct
[4] == 'O'){
282 } else if (ct
[4] == 'N'){
287 RPC_INT
, atoi (&ct
[17]), /* sec */
288 RPC_INT
, atoi (&ct
[14]), /* min */
289 RPC_INT
, atoi (&ct
[11]), /* hour */
290 RPC_INT
, atoi (&ct
[8]), /* mday */
291 RPC_INT
, atoi (&ct
[20]), /* year */
292 RPC_INT
, month
, /* month */
295 long ltime
= (long) time
;
298 g_snprintf (buf
, sizeof(buf
), "%lx", ltime
);
305 static void send_stat_info (struct stat
*st
)
309 #ifdef HAVE_ST_BLOCKS
316 mylong
= st
->st_rdev
;
320 rpc_send (msock
, RPC_INT
, (long) mylong
,
321 RPC_INT
, (long) st
->st_ino
,
322 RPC_INT
, (long) st
->st_mode
,
323 RPC_INT
, (long) st
->st_nlink
,
324 RPC_INT
, (long) st
->st_uid
,
325 RPC_INT
, (long) st
->st_gid
,
326 RPC_INT
, (long) st
->st_size
,
327 RPC_INT
, (long) blocks
, RPC_END
);
328 send_time (msock
, st
->st_atime
);
329 send_time (msock
, st
->st_mtime
);
330 send_time (msock
, st
->st_ctime
);
333 static void do_lstat (void)
339 rpc_get (msock
, RPC_STRING
, &file
, RPC_END
);
340 n
= lstat (file
, &st
);
341 send_status (n
, errno
);
343 send_stat_info (&st
);
347 static void do_fstat (void)
353 rpc_get (msock
, RPC_INT
, &handle
, RPC_END
);
354 n
= fstat (handle
, &st
);
355 send_status (n
, errno
);
359 send_stat_info (&st
);
362 static void do_stat (void)
368 rpc_get (msock
, RPC_STRING
, &file
, RPC_END
);
370 n
= stat (file
, &st
);
371 send_status (n
, errno
);
373 send_stat_info (&st
);
379 /* {{{ Directory lookup operations */
383 DIR *dirs
[OPENDIR_HANDLES
];
384 char *names
[OPENDIR_HANDLES
];
387 static void close_handle (int handle
)
389 if (mcfs_DIR
.used
> 0) mcfs_DIR
.used
--;
390 if (mcfs_DIR
.dirs
[handle
])
391 closedir (mcfs_DIR
.dirs
[handle
]);
392 if (mcfs_DIR
.names
[handle
])
393 g_free (mcfs_DIR
.names
[handle
]);
394 mcfs_DIR
.dirs
[handle
] = 0;
395 mcfs_DIR
.names
[handle
] = 0;
398 static void do_opendir (void)
404 rpc_get (msock
, RPC_STRING
, &arg
, RPC_END
);
406 if (mcfs_DIR
.used
== OPENDIR_HANDLES
){
407 send_status (-1, ENFILE
); /* Error */
413 for (i
= 0; i
< OPENDIR_HANDLES
; i
++){
414 if (mcfs_DIR
.dirs
[i
] == 0){
421 send_status (-1, EMFILE
);
424 fprintf (stderr
, "OOPS! you have found a bug in mc - do_opendir()!\n");
428 if (verbose
) printf ("handle=%d\n", handle
);
431 mcfs_DIR
.dirs
[handle
] = p
;
432 mcfs_DIR
.names
[handle
] = arg
;
435 /* Because 0 is an error value */
436 rpc_send (msock
, RPC_INT
, handle
+1, RPC_INT
, 0, RPC_END
);
439 send_status (-1, errno
);
444 /* Sends the complete directory listing, as well as the stat information */
445 static void do_readdir (void)
447 struct dirent
*dirent
;
452 rpc_get (msock
, RPC_INT
, &handle
, RPC_END
);
455 rpc_send (msock
, RPC_INT
, 0, RPC_END
);
459 /* We incremented it in opendir */
462 while ((dirent
= readdir (mcfs_DIR
.dirs
[handle
]))){
463 int length
= NLENGTH (dirent
);
465 rpc_send (msock
, RPC_INT
, length
, RPC_END
);
466 rpc_send (msock
, RPC_BLOCK
, length
, dirent
->d_name
, RPC_END
);
467 fname
= g_strconcat (mcfs_DIR
.names
[handle
],
468 PATH_SEP_STR
, dirent
->d_name
, NULL
);
469 n
= lstat (fname
, &st
);
470 send_status (n
, errno
);
473 send_stat_info (&st
);
475 rpc_send (msock
, RPC_INT
, 0, RPC_END
);
478 static void do_closedir (void)
482 rpc_get (msock
, RPC_INT
, &handle
, RPC_END
);
483 close_handle (handle
-1);
488 /* {{{ Operations with one and two file name argument */
490 static void do_chdir (void)
495 rpc_get (msock
, RPC_STRING
, &file
, RPC_END
);
497 status
= chdir (file
);
498 send_status (status
, errno
);
502 static void do_rmdir (void)
507 rpc_get (msock
, RPC_STRING
, &file
, RPC_END
);
509 status
= rmdir (file
);
510 send_status (status
, errno
);
514 static void do_mkdir (void)
519 rpc_get (msock
, RPC_STRING
, &file
, RPC_INT
, &mode
, RPC_END
);
521 status
= mkdir (file
, mode
);
522 send_status (status
, errno
);
526 static void do_mknod (void)
529 int mode
, dev
, status
;
531 rpc_get (msock
, RPC_STRING
, &file
, RPC_INT
, &mode
, RPC_INT
, &dev
, RPC_END
);
533 status
= mknod (file
, mode
, dev
);
534 send_status (status
, errno
);
538 static void do_readlink (void)
544 rpc_get (msock
, RPC_STRING
, &file
, RPC_END
);
545 n
= readlink (file
, buffer
, 2048);
546 send_status (n
, errno
);
549 rpc_send (msock
, RPC_STRING
, buffer
, RPC_END
);
554 static void do_unlink (void)
559 rpc_get (msock
, RPC_STRING
, &file
, RPC_END
);
560 status
= unlink (file
);
561 send_status (status
, errno
);
565 static void do_rename (void)
570 rpc_get (msock
, RPC_STRING
, &f1
, RPC_STRING
, &f2
, RPC_END
);
571 status
= rename (f1
, f2
);
572 send_status (status
, errno
);
573 g_free (f1
); g_free (f2
);
576 static void do_symlink (void)
581 rpc_get (msock
, RPC_STRING
, &f1
, RPC_STRING
, &f2
, RPC_END
);
582 status
= symlink (f1
, f2
);
583 send_status (status
, errno
);
584 g_free (f1
); g_free (f2
);
587 static void do_link (void)
592 rpc_get (msock
, RPC_STRING
, &f1
, RPC_STRING
, &f2
, RPC_END
);
593 status
= link (f1
, f2
);
594 send_status (status
, errno
);
595 g_free (f1
); g_free (f2
);
601 /* {{{ Misc commands */
603 static void do_gethome (void)
605 rpc_send (msock
, RPC_STRING
, (home_dir
) ? home_dir
: "/", RPC_END
);
608 static void do_getupdir (void)
610 rpc_send (msock
, RPC_STRING
, (up_dir
) ? up_dir
: "/", RPC_END
);
613 static void do_chmod (void)
618 rpc_get (msock
, RPC_STRING
, &file
, RPC_INT
, &mode
, RPC_END
);
619 status
= chmod (file
, mode
);
620 send_status (status
, errno
);
624 static void do_chown (void)
627 int owner
, group
, status
;
629 rpc_get (msock
, RPC_STRING
, &file
,RPC_INT
, &owner
, RPC_INT
,&group
,RPC_END
);
630 status
= chown (file
, owner
, group
);
631 send_status (status
, errno
);
635 static void do_utime (void)
643 struct utimbuf times
;
645 rpc_get (msock
, RPC_STRING
, &file
,
649 sscanf (as
, "%lx", &atime
);
650 sscanf (ms
, "%lx", &mtime
);
651 if (verbose
) printf ("Got a = %s, m = %s, comp a = %ld, m = %ld\n",
652 as
, ms
, atime
, mtime
);
655 times
.actime
= (time_t) atime
;
656 times
.modtime
= (time_t) mtime
;
657 status
= utime (file
, ×
);
658 send_status (status
, errno
);
662 static void do_quit (void)
675 mc_pam_conversation (int messages
, const struct pam_message
**msg
,
676 struct pam_response
**resp
, void *appdata_ptr
)
678 struct pam_response
*r
;
679 struct user_pass
*up
= appdata_ptr
;
682 r
= g_new (struct pam_response
, messages
);
687 for (status
= PAM_SUCCESS
; messages
--; msg
++, r
++){
688 switch ((*msg
)->msg_style
){
690 case PAM_PROMPT_ECHO_ON
:
691 r
->resp
= g_strdup (up
->username
);
692 r
->resp_retcode
= PAM_SUCCESS
;
695 case PAM_PROMPT_ECHO_OFF
:
696 r
->resp
= g_strdup (up
->password
);
697 r
->resp_retcode
= PAM_SUCCESS
;
702 r
->resp_retcode
= PAM_SUCCESS
;
707 r
->resp_retcode
= PAM_SUCCESS
;
714 static struct pam_conv conv
= { &mc_pam_conversation
, NULL
};
717 /* Return 0 if authentication failed, 1 otherwise */
719 mc_pam_auth (char *username
, char *password
)
725 up
.username
= username
;
726 up
.password
= password
;
727 conv
.appdata_ptr
= &up
;
729 if ((status
= pam_start("mcserv", username
, &conv
, &pamh
)) != PAM_SUCCESS
)
731 if ((status
= pam_authenticate (pamh
, 0)) != PAM_SUCCESS
)
733 if ((status
= pam_acct_mgmt (pamh
, 0)) != PAM_SUCCESS
)
735 if ((status
= pam_setcred (pamh
, PAM_ESTABLISH_CRED
)) != PAM_SUCCESS
)
737 pam_end (pamh
, status
);
741 pam_end (pamh
, status
);
745 #else /* Code for non-PAM authentication */
747 /* Keep reading until we find a \n */
748 static int next_line (int socket
)
753 if (read (socket
, &c
, 1) <= 0)
760 static int ftp_answer (int sock
, char *text
)
765 socket_read_block (sock
, answer
, 3);
767 if (strcmp (answer
, text
) == 0)
772 static int do_ftp_auth (char *username
, char *password
)
774 struct sockaddr_in local_address
;
775 unsigned long inaddr
;
779 memset ((char *) &local_address
, 0, sizeof (local_address
));
781 local_address
.sin_family
= AF_INET
;
782 /* FIXME: extract the ftp port with the proper function */
783 local_address
.sin_port
= htons (21);
785 /* Convert localhost to usable format */
786 if ((inaddr
= inet_addr ("127.0.0.1")) != -1)
787 memcpy ((char *) &local_address
.sin_addr
, (char *) &inaddr
,
790 if ((my_socket
= socket (AF_INET
, SOCK_STREAM
, 0)) < 0){
791 if (!isDaemon
) fprintf (stderr
, "do_auth: can't create socket\n");
794 if (connect (my_socket
, (struct sockaddr
*) &local_address
,
795 sizeof (local_address
)) < 0){
797 "do_auth: can't connect to ftp daemon for authentication\n");
801 send_string (my_socket
, "user ");
802 send_string (my_socket
, username
);
803 send_string (my_socket
, "\r\n");
804 if (!ftp_answer (my_socket
, "331")){
805 send_string (my_socket
, "quit\r\n");
809 next_line (my_socket
); /* Eat all the line */
810 send_string (my_socket
, "pass ");
811 send_string (my_socket
, password
);
812 send_string (my_socket
, "\r\n");
813 socket_read_block (my_socket
, answer
, 3);
815 send_string (my_socket
, "\r\n");
816 send_string (my_socket
, "quit\r\n");
818 if (strcmp (answer
, "230") == 0)
823 static int do_classic_auth (char *username
, char *password
)
829 extern char *pw_encrypt (char *, char *);
831 #ifdef NEED_CRYPT_PROTOTYPE
832 extern char *crypt (const char *, const char *);
836 if ((this = getpwnam (username
)) == 0)
840 if ((spw
= getspnam (username
)) == NULL
)
841 this->pw_passwd
= "*";
843 this->pw_passwd
= spw
->sp_pwdp
;
844 if (strcmp (pw_encrypt (password
, this->pw_passwd
), this->pw_passwd
) == 0)
850 if (strcmp (crypt (password
, this->pw_passwd
), this->pw_passwd
) == 0){
861 #endif /* non-PAM authentication */
863 /* Try to authenticate the user based on:
864 - PAM if the system has it, else it checks:
865 - pwdauth if the system supports it.
866 - conventional auth (check salt on /etc/passwd, crypt, and compare
867 - try to contact the local ftp server and login (if -f flag used)
870 do_auth (char *username
, char *password
)
875 if (strcmp (username
, "anonymous") == 0)
879 if (mc_pam_auth (username
, password
) == 0)
881 #else /* if there is no pam */
883 if (pwdauth (username
, password
) == 0)
887 if (do_classic_auth (username
, password
))
890 auth
= do_ftp_auth (username
, password
);
896 this = getpwnam (username
);
900 if (chdir (this->pw_dir
) == -1)
903 if (this->pw_dir
[strlen (this->pw_dir
) - 1] == '/')
904 home_dir
= g_strdup (this->pw_dir
);
906 home_dir
= g_malloc (strlen (this->pw_dir
) + 2);
908 strcpy (home_dir
, this->pw_dir
);
909 strcat (home_dir
, "/");
915 if (setgid (this->pw_gid
) == -1)
918 #ifdef HAVE_INITGROUPS
920 if (NGROUPS_MAX
> 1 && initgroups (this->pw_name
, this->pw_gid
))
925 #if defined (HAVE_SETUID)
926 if (setuid (this->pw_uid
))
928 #elif defined (HAVE_SETREUID)
929 if (setreuid (this->pw_uid
, this->pw_uid
))
933 /* If the setuid call failed, then deny access */
934 /* This should fix the problem on those machines with strange setups */
935 if (getuid () != this->pw_uid
)
938 if (strcmp (username
, "ftp") == 0)
939 chroot (this->pw_dir
);
946 static int do_rauth (int socket
)
948 struct sockaddr_in from
;
951 if (getpeername(0, (struct sockaddr
*)&from
, &fromlen
) < 0)
953 from
.sin_port
= ntohs ((unsigned short) from
.sin_port
);
955 /* Strange, this should not happend */
956 if (from
.sin_family
!= AF_INET
)
959 hp
= gethostbyaddr((char *)&fromp
.sin_addr
, sizeof (struct in_addr
),
965 static int do_rauth (int msock
)
970 static void login_reply (int logged_in
)
972 rpc_send (msock
, RPC_INT
,
973 logged_in
? MC_LOGINOK
: MC_INVALID_PASS
,
977 /* FIXME: Implement the anonymous login */
978 static void do_login (void)
984 rpc_get (msock
, RPC_LIMITED_STRING
, &up_dir
, RPC_LIMITED_STRING
, &username
, RPC_END
);
985 if (verbose
) printf ("username: %s\n", username
);
988 logged_in
= do_rauth (msock
);
990 login_reply (logged_in
);
994 rpc_send (msock
, RPC_INT
, MC_NEED_PASSWORD
, RPC_END
);
995 rpc_get (msock
, RPC_INT
, &result
, RPC_END
);
996 if (result
== MC_QUIT
)
998 if (result
!= MC_PASS
){
999 if (verbose
) printf ("do_login: Unknown response: %d\n", result
);
1002 rpc_get (msock
, RPC_LIMITED_STRING
, &password
, RPC_END
);
1003 logged_in
= do_auth (username
, password
);
1005 login_reply (logged_in
);
1010 /* {{{ Server and dispatching functions */
1012 /* This structure must be kept in synch with mcfs.h enums */
1014 static struct _command
{
1016 void (*callback
)(void);
1018 { "open", do_open
},
1019 { "close", do_close
},
1020 { "read", do_read
},
1021 { "write", do_write
},
1022 { "opendir", do_opendir
},
1023 { "readdir", do_readdir
},
1024 { "closedir", do_closedir
},
1025 { "stat ", do_stat
},
1026 { "lstat ", do_lstat
},
1027 { "fstat", do_fstat
},
1028 { "chmod", do_chmod
},
1029 { "chown", do_chown
},
1030 { "readlink ", do_readlink
},
1031 { "unlink", do_unlink
},
1032 { "rename", do_rename
},
1033 { "chdir ", do_chdir
},
1034 { "lseek", do_lseek
},
1035 { "rmdir", do_rmdir
},
1036 { "symlink", do_symlink
},
1037 { "mknod", do_mknod
},
1038 { "mkdir", do_mkdir
},
1039 { "link", do_link
},
1040 { "gethome", do_gethome
},
1041 { "getupdir", do_getupdir
},
1042 { "login", do_login
},
1043 { "quit", do_quit
},
1044 { "utime", do_utime
},
1047 static int ncommands
= sizeof(commands
)/sizeof(struct _command
);
1049 static void exec_command (int command
)
1052 command
>= ncommands
||
1053 commands
[command
].command
== 0){
1054 fprintf (stderr
, "Got unknown command: %d\n", command
);
1057 if (verbose
) printf ("Command: %s\n", commands
[command
].command
);
1058 (*commands
[command
].callback
)();
1061 static void check_version (void)
1065 rpc_get (msock
, RPC_INT
, &version
, RPC_END
);
1067 version
<= RPC_PROGVER
)
1068 rpc_send (msock
, RPC_INT
, MC_VERSION_OK
, RPC_END
);
1070 rpc_send (msock
, RPC_INT
, MC_VERSION_MISMATCH
, RPC_END
);
1072 clnt_version
= version
;
1075 /* This routine is called by rpc_get/rpc_send when the connection is closed */
1076 void tcp_invalidate_socket (int sock
)
1078 if (verbose
) printf ("Connection closed\n");
1082 static void server (int sock
)
1091 if (rpc_get (sock
, RPC_INT
, &command
, RPC_END
) &&
1092 (logged_in
|| command
== MC_LOGIN
))
1093 exec_command (command
);
1094 } while (!quit_server
);
1099 /* {{{ Net support code */
1101 static char *get_client (int portnum
)
1103 int sock
, clilen
, newsocket
;
1104 struct sockaddr_in client_address
, server_address
;
1106 char hostname
[255];
1112 if ((sock
= socket (AF_INET
, SOCK_STREAM
, 0)) < 0)
1113 return "Cannot create socket";
1115 /* Use this to debug: */
1116 if (setsockopt (sock
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &yes
, sizeof (yes
)) < 0)
1117 return "setsockopt failed";
1119 gethostname (hostname
, 255);
1120 if (verbose
) printf ("hostname=%s\n", hostname
);
1121 hp
= gethostbyname (hostname
);
1123 if (hp
== 0 && (me
= getenv("HOSTNAME")) && (0 == strcmp(hostname
, me
)))
1124 hp
= gethostbyname ("localhost");
1129 memset ((char *) &server_address
, 0, sizeof (server_address
));
1130 server_address
.sin_family
= hp
->h_addrtype
;
1131 server_address
.sin_addr
.s_addr
= htonl (INADDR_ANY
);
1132 server_address
.sin_port
= htons (portnum
);
1134 if (bind (sock
, (struct sockaddr
*) &server_address
,
1135 sizeof (server_address
)) < 0)
1136 return "Cannot bind";
1143 clilen
= sizeof (client_address
);
1144 newsocket
= accept (sock
, (struct sockaddr
*) &client_address
,
1147 if (isDaemon
&& (child
= fork())) {
1151 waitpid (child
, &status
, 0);
1155 if (isDaemon
&& fork()) exit (0);
1163 #ifdef HAVE_PMAP_SET
1164 static void signal_int_handler (int sig
)
1166 pmap_unset (RPC_PROGNUM
, RPC_PROGVER
);
1170 #ifndef IPPORT_RESERVED
1171 #define IPPORT_RESERVED 1024;
1174 static int get_port_number (void)
1178 #ifdef HAVE_RRESVPORT
1179 int start_port
= IPPORT_RESERVED
;
1181 port
= rresvport (&start_port
);
1183 if (geteuid () == 0){
1184 fprintf (stderr
, "Could not bind the server on a reserved port\n");
1185 DO_QUIT_NONVOID (-1);
1193 port
= mcserver_port
;
1198 static void register_port (int portnum
, int abort_if_fail
)
1200 #ifdef HAVE_PMAP_SET
1201 /* Register our service with the portmapper */
1202 /* protocol: pmap_set (prognum, versnum, protocol, portp) */
1204 if (pmap_set (RPC_PROGNUM
, RPC_PROGVER
, IPPROTO_TCP
, portnum
))
1205 signal (SIGINT
, signal_int_handler
);
1207 fprintf (stderr
, "Could not register service with portmapper\n");
1214 "This system lacks port registration, try using the -p\n"
1215 "flag to force installation at a given port");
1222 int main (int argc
, char *argv
[])
1225 extern char *optarg
;
1228 while ((c
= getopt (argc
, argv
, "fdiqp:v")) != -1){
1248 portnum
= atoi (optarg
);
1260 fprintf (stderr
, "Usage is: mcserv [options] [-p portnum]\n\n"
1262 "-d become a daemon (sets -q)\n"
1264 /* "-r use rhost based authentication\n" */
1266 "-f force ftp authentication\n"
1269 "-p to specify a port number to listen\n");
1275 if (isDaemon
&& fork()) exit (0);
1278 portnum
= get_port_number ();
1280 if (portnum
!= -1) {
1281 register_port (portnum
, 0);
1283 printf ("Using port %d\n", portnum
);
1284 if ((result
= get_client (portnum
)))
1286 #ifdef HAVE_PMAP_SET
1288 pmap_unset (RPC_PROGNUM
, RPC_PROGVER
);
1294 /* FIXME: This function should not be used in mcserv */
1295 void vfs_die( char *m
)