1 /* Server for the Midnight Commander Virtual File System.
3 Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
4 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
7 Miguel de Icaza, 1995, 1997,
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27 * \brief Source: server for the Midnight Commander Virtual File System
28 * \author Miguel de Icaza
29 * \author Andrej Borsenkow
30 * \date 1995, 1996, 1997
32 * \todo opendir instead of keeping its table of file handles could return
33 * the pointer and expect the client to send a proper value back each
34 * time :-) We should use syslog to register login/logout.
37 /* {{{ Includes and global variables */
49 # include <sys/param.h>
51 # define NGROUPS_MAX NGROUPS
55 #include <sys/types.h>
64 /* Network include files */
65 #include <sys/socket.h>
66 #include <netinet/in.h>
68 #ifdef HAVE_ARPA_INET_H
69 #include <arpa/inet.h>
73 # include <rpc/pmap_prot.h>
74 # ifdef HAVE_RPC_PMAP_CLNT_H
75 # include <rpc/pmap_clnt.h>
80 # if !defined(HAVE_SECURITY_PAM_MISC_H)
85 /* Authentication include files */
88 # include <security/pam_misc.h>
89 # ifndef PAM_ESTABLISH_CRED
90 # define PAM_ESTABLISH_CRED PAM_CRED_ESTABLISH
93 #endif /* !HAVE_PAM */
97 #endif /* !HAVE_CRYPT_H */
102 # ifdef HAVE_SHADOW_SHADOW_H
103 # include <shadow/shadow.h>
108 * GNU gettext defines printf to libintl_printf on platforms that lack
109 * a native printf(3) capable of all POSIX features.
112 #include "../src/global.h"
114 #include "../src/wtools.h" /* message() */
115 #include "../src/main.h" /* print_vfs_message */
119 #include "mcfsutil.h"
123 # define INADDR_NONE (0xffffffffU)
126 /* replacement for g_free() from glib */
128 #define g_free(x) do {if (x) free (x);} while (0)
130 /* We don't care about SIGPIPE */
133 /* The socket from which we accept commands */
136 /* Requested version number from client */
137 static int clnt_version
;
139 /* If non zero, we accept further commands */
143 const char *home_dir
= NULL
;
147 /* Were we started from inetd? */
148 int inetd_started
= 0;
150 /* Are we running as a daemon? */
159 /* port number in which we listen to connections,
160 * if zero, we try to contact the portmapper to get a port, and
161 * if it's not possible, then we use a hardcoded value
165 /* if the server will use rcmd based authentication (hosts.equiv .rhosts) */
168 #define OPENDIR_HANDLES 8
170 #define DO_QUIT_VOID() \
177 /* Only used by get_port_number */
178 #define DO_QUIT_NONVOID(a) \
187 static int quit_server
;
188 static int return_code
;
192 /* {{{ Misc routines */
195 send_status (int status
, int errno_number
)
197 rpc_send (msock
, RPC_INT
, status
, RPC_INT
, errno_number
, RPC_END
);
203 /* {{{ File with handle operations */
208 int handle
, flags
, mode
;
211 rpc_get (msock
, RPC_STRING
, &arg
, RPC_INT
, &flags
, RPC_INT
, &mode
,
214 handle
= open (arg
, flags
, mode
);
215 send_status (handle
, errno
);
222 int handle
, count
, n
;
225 rpc_get (msock
, RPC_INT
, &handle
, RPC_INT
, &count
, RPC_END
);
226 data
= malloc (count
);
228 send_status (-1, ENOMEM
);
232 printf ("count=%d\n", count
);
233 n
= read (handle
, data
, count
);
235 printf ("result=%d\n", n
);
237 send_status (-1, errno
);
241 rpc_send (msock
, RPC_BLOCK
, n
, data
, RPC_END
);
249 int handle
, count
, status
, written
= 0;
252 rpc_get (msock
, RPC_INT
, &handle
, RPC_INT
, &count
, RPC_END
);
255 int nbytes
= count
> 8192 ? 8192 : count
;
257 rpc_get (msock
, RPC_BLOCK
, nbytes
, buf
, RPC_END
);
258 status
= write (handle
, buf
, nbytes
);
260 send_status (status
, errno
);
263 /* FIXED: amount written must be returned to caller */
265 if (status
< nbytes
) {
266 send_status (written
, errno
);
271 send_status (written
, errno
);
277 int handle
, offset
, whence
, status
;
279 rpc_get (msock
, RPC_INT
, &handle
, RPC_INT
, &offset
, RPC_INT
, &whence
,
281 status
= lseek (handle
, offset
, whence
);
282 send_status (status
, errno
);
290 rpc_get (msock
, RPC_INT
, &handle
, RPC_END
);
291 status
= close (handle
);
292 send_status (status
, errno
);
297 /* {{{ Stat family routines */
300 send_time (int sock
, time_t time
)
302 if (clnt_version
== 1) {
307 ct
[3] = ct
[10] = ct
[13] = ct
[16] = ct
[19] = 0;
309 /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
314 month
= (ct
[6] == 'n') ? 5 : 6;
315 } else if (ct
[4] == 'F') {
317 } else if (ct
[4] == 'M') {
318 month
= (ct
[6] == 'r') ? 2 : 5;
319 } else if (ct
[4] == 'A') {
320 month
= (ct
[5] == 'p') ? 3 : 7;
321 } else if (ct
[4] == 'S') {
323 } else if (ct
[4] == 'O') {
325 } else if (ct
[4] == 'N') {
329 rpc_send (msock
, RPC_INT
, atoi (&ct
[17]), /* sec */
330 RPC_INT
, atoi (&ct
[14]), /* min */
331 RPC_INT
, atoi (&ct
[11]), /* hour */
332 RPC_INT
, atoi (&ct
[8]), /* mday */
333 RPC_INT
, atoi (&ct
[20]), /* year */
334 RPC_INT
, month
, /* month */
337 long ltime
= (long) time
;
340 snprintf (buf
, sizeof (buf
), "%lx", ltime
);
341 rpc_send (msock
, RPC_STRING
, buf
, RPC_END
);
346 send_stat_info (struct stat
*st
)
350 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
356 #ifdef HAVE_STRUCT_STAT_ST_RDEV
357 mylong
= st
->st_rdev
;
361 rpc_send (msock
, RPC_INT
, (long) mylong
, RPC_INT
, (long) st
->st_ino
,
362 RPC_INT
, (long) st
->st_mode
, RPC_INT
, (long) st
->st_nlink
,
363 RPC_INT
, (long) st
->st_uid
, RPC_INT
, (long) st
->st_gid
,
364 RPC_INT
, (long) st
->st_size
, RPC_INT
, (long) blocks
,
366 send_time (msock
, st
->st_atime
);
367 send_time (msock
, st
->st_mtime
);
368 send_time (msock
, st
->st_ctime
);
378 rpc_get (msock
, RPC_STRING
, &file
, RPC_END
);
379 n
= lstat (file
, &st
);
380 send_status (n
, errno
);
382 send_stat_info (&st
);
393 rpc_get (msock
, RPC_INT
, &handle
, RPC_END
);
394 n
= fstat (handle
, &st
);
395 send_status (n
, errno
);
399 send_stat_info (&st
);
409 rpc_get (msock
, RPC_STRING
, &file
, RPC_END
);
411 n
= stat (file
, &st
);
412 send_status (n
, errno
);
414 send_stat_info (&st
);
420 /* {{{ Directory lookup operations */
424 DIR *dirs
[OPENDIR_HANDLES
];
425 char *names
[OPENDIR_HANDLES
];
429 close_handle (int handle
)
431 if (mcfs_DIR
.used
> 0)
433 if (mcfs_DIR
.dirs
[handle
])
434 closedir (mcfs_DIR
.dirs
[handle
]);
435 g_free (mcfs_DIR
.names
[handle
]);
436 mcfs_DIR
.dirs
[handle
] = 0;
437 mcfs_DIR
.names
[handle
] = 0;
447 rpc_get (msock
, RPC_STRING
, &arg
, RPC_END
);
449 if (mcfs_DIR
.used
== OPENDIR_HANDLES
) {
450 send_status (-1, ENFILE
); /* Error */
456 for (i
= 0; i
< OPENDIR_HANDLES
; i
++) {
457 if (mcfs_DIR
.dirs
[i
] == 0) {
464 send_status (-1, EMFILE
);
468 "OOPS! you have found a bug in mc - do_opendir()!\n");
473 printf ("handle=%d\n", handle
);
476 mcfs_DIR
.dirs
[handle
] = p
;
477 mcfs_DIR
.names
[handle
] = arg
;
480 /* Because 0 is an error value */
481 rpc_send (msock
, RPC_INT
, handle
+ 1, RPC_INT
, 0, RPC_END
);
484 send_status (-1, errno
);
489 /* Sends the complete directory listing, as well as the stat information */
493 struct dirent
*dirent
;
497 rpc_get (msock
, RPC_INT
, &handle
, RPC_END
);
500 rpc_send (msock
, RPC_INT
, 0, RPC_END
);
504 /* We incremented it in opendir */
507 while ((dirent
= readdir (mcfs_DIR
.dirs
[handle
]))) {
510 int length
= NLENGTH (dirent
);
512 rpc_send (msock
, RPC_INT
, length
, RPC_END
);
513 rpc_send (msock
, RPC_BLOCK
, length
, dirent
->d_name
, RPC_END
);
515 strlen (mcfs_DIR
.names
[handle
]) + strlen (dirent
->d_name
) + 2;
516 fname
= malloc (fname_len
);
517 snprintf (fname
, fname_len
, "%s/%s", mcfs_DIR
.names
[handle
],
519 n
= lstat (fname
, &st
);
521 send_status (n
, errno
);
523 send_stat_info (&st
);
525 rpc_send (msock
, RPC_INT
, 0, RPC_END
);
533 rpc_get (msock
, RPC_INT
, &handle
, RPC_END
);
534 close_handle (handle
- 1);
539 /* {{{ Operations with one and two file name argument */
547 rpc_get (msock
, RPC_STRING
, &file
, RPC_END
);
549 status
= chdir (file
);
550 send_status (status
, errno
);
560 rpc_get (msock
, RPC_STRING
, &file
, RPC_END
);
562 status
= rmdir (file
);
563 send_status (status
, errno
);
573 rpc_get (msock
, RPC_STRING
, &file
, RPC_INT
, &mode
, RPC_END
);
575 status
= mkdir (file
, mode
);
576 send_status (status
, errno
);
584 int mode
, dev
, status
;
586 rpc_get (msock
, RPC_STRING
, &file
, RPC_INT
, &mode
, RPC_INT
, &dev
,
589 status
= mknod (file
, mode
, dev
);
590 send_status (status
, errno
);
601 rpc_get (msock
, RPC_STRING
, &file
, RPC_END
);
602 n
= readlink (file
, buffer
, 2048 - 1);
603 send_status (n
, errno
);
606 rpc_send (msock
, RPC_STRING
, buffer
, RPC_END
);
617 rpc_get (msock
, RPC_STRING
, &file
, RPC_END
);
618 status
= unlink (file
);
619 send_status (status
, errno
);
629 rpc_get (msock
, RPC_STRING
, &f1
, RPC_STRING
, &f2
, RPC_END
);
630 status
= rename (f1
, f2
);
631 send_status (status
, errno
);
642 rpc_get (msock
, RPC_STRING
, &f1
, RPC_STRING
, &f2
, RPC_END
);
643 status
= symlink (f1
, f2
);
644 send_status (status
, errno
);
655 rpc_get (msock
, RPC_STRING
, &f1
, RPC_STRING
, &f2
, RPC_END
);
656 status
= link (f1
, f2
);
657 send_status (status
, errno
);
665 /* {{{ Misc commands */
670 rpc_send (msock
, RPC_STRING
, (home_dir
) ? home_dir
: "/", RPC_END
);
676 rpc_send (msock
, RPC_STRING
, (up_dir
) ? up_dir
: "/", RPC_END
);
685 rpc_get (msock
, RPC_STRING
, &file
, RPC_INT
, &mode
, RPC_END
);
686 status
= chmod (file
, mode
);
687 send_status (status
, errno
);
695 int owner
, group
, status
;
697 rpc_get (msock
, RPC_STRING
, &file
, RPC_INT
, &owner
, RPC_INT
, &group
,
699 status
= chown (file
, owner
, group
);
700 send_status (status
, errno
);
713 struct utimbuf times
;
715 rpc_get (msock
, RPC_STRING
, &file
, RPC_STRING
, &as
, RPC_STRING
, &ms
,
717 sscanf (as
, "%lx", &atime
);
718 sscanf (ms
, "%lx", &mtime
);
720 printf ("Got a = %s, m = %s, comp a = %ld, m = %ld\n", as
, ms
,
724 times
.actime
= (time_t) atime
;
725 times
.modtime
= (time_t) mtime
;
726 status
= utime (file
, ×
);
727 send_status (status
, errno
);
740 const char *username
;
741 const char *password
;
745 mc_pam_conversation (int messages
, const struct pam_message
**msg
,
746 struct pam_response
**resp
, void *appdata_ptr
)
748 struct pam_response
*r
;
749 struct user_pass
*up
= appdata_ptr
;
752 r
= (struct pam_response
*) malloc (sizeof (struct pam_response
) *
758 for (status
= PAM_SUCCESS
; messages
--; msg
++, r
++) {
759 switch ((*msg
)->msg_style
) {
761 case PAM_PROMPT_ECHO_ON
:
762 r
->resp
= strdup (up
->username
);
763 r
->resp_retcode
= PAM_SUCCESS
;
766 case PAM_PROMPT_ECHO_OFF
:
767 r
->resp
= strdup (up
->password
);
768 r
->resp_retcode
= PAM_SUCCESS
;
773 r
->resp_retcode
= PAM_SUCCESS
;
778 r
->resp_retcode
= PAM_SUCCESS
;
785 static struct pam_conv conv
= { &mc_pam_conversation
, NULL
};
788 /* Return 0 if authentication failed, 1 otherwise */
790 mc_pam_auth (const char *username
, const char *password
)
796 up
.username
= username
;
797 up
.password
= password
;
798 conv
.appdata_ptr
= &up
;
801 pam_start ("mcserv", username
, &conv
, &pamh
)) != PAM_SUCCESS
)
803 if ((status
= pam_authenticate (pamh
, 0)) != PAM_SUCCESS
)
805 if ((status
= pam_acct_mgmt (pamh
, 0)) != PAM_SUCCESS
)
807 if ((status
= pam_setcred (pamh
, PAM_ESTABLISH_CRED
)) != PAM_SUCCESS
)
809 pam_end (pamh
, status
);
813 pam_end (pamh
, status
);
817 #else /* !HAVE_PAM */
819 /* Keep reading until we find a \n */
821 next_line (int socket
)
826 if (read (socket
, &c
, 1) <= 0)
834 ftp_answer (int sock
, const char *text
)
839 socket_read_block (sock
, answer
, 3);
841 if (strcmp (answer
, text
) == 0)
847 send_string (int sock
, const char *string
)
849 return socket_write_block (sock
, string
, strlen (string
));
853 do_ftp_auth (const char *username
, const char *password
)
855 struct sockaddr_in local_address
;
856 unsigned long inaddr
;
860 memset ((char *) &local_address
, 0, sizeof (local_address
));
862 local_address
.sin_family
= AF_INET
;
863 /* FIXME: extract the ftp port with the proper function */
864 local_address
.sin_port
= htons (21);
866 /* Convert localhost to usable format */
867 if ((inaddr
= inet_addr ("127.0.0.1")) != INADDR_NONE
)
868 memcpy ((char *) &local_address
.sin_addr
, (char *) &inaddr
,
871 if ((my_socket
= socket (AF_INET
, SOCK_STREAM
, 0)) < 0) {
873 fprintf (stderr
, "do_auth: can't create socket\n");
877 (my_socket
, (struct sockaddr
*) &local_address
,
878 sizeof (local_address
)) < 0) {
880 "do_auth: can't connect to ftp daemon for authentication\n");
884 send_string (my_socket
, "user ");
885 send_string (my_socket
, username
);
886 send_string (my_socket
, "\r\n");
887 if (!ftp_answer (my_socket
, "331")) {
888 send_string (my_socket
, "quit\r\n");
892 next_line (my_socket
); /* Eat all the line */
893 send_string (my_socket
, "pass ");
894 send_string (my_socket
, password
);
895 send_string (my_socket
, "\r\n");
896 socket_read_block (my_socket
, answer
, 3);
898 send_string (my_socket
, "\r\n");
899 send_string (my_socket
, "quit\r\n");
901 if (strcmp (answer
, "230") == 0)
908 do_classic_auth (const char *username
, const char *password
)
911 const char *encr_pwd
= NULL
;
917 if ((pw
= getpwnam (username
)) == 0)
923 /* Password expiration is not checked! */
924 if ((spw
= getspnam (username
)) == NULL
)
927 encr_pwd
= spw
->sp_pwdp
;
931 encr_pwd
= pw
->pw_passwd
;
934 if (strcmp (crypt (password
, encr_pwd
), encr_pwd
) == 0)
940 #endif /* HAVE_CRYPT */
941 #endif /* !HAVE_PAM */
943 /* Try to authenticate the user based on:
944 - PAM if the system has it, else it checks:
945 - pwdauth if the system supports it.
946 - conventional auth (check salt on /etc/passwd, crypt, and compare
947 - try to contact the local ftp server and login (if -f flag used)
950 do_auth (const char *username
, const char *password
)
955 if (strcmp (username
, "anonymous") == 0)
959 if (mc_pam_auth (username
, password
) == 0)
961 #else /* if there is no pam */
963 if (pwdauth (username
, password
) == 0)
968 if (do_classic_auth (username
, password
))
973 auth
= do_ftp_auth (username
, password
);
979 this = getpwnam (username
);
983 if (chdir (this->pw_dir
) == -1)
986 if (this->pw_dir
[strlen (this->pw_dir
) - 1] == '/')
987 home_dir
= strdup (this->pw_dir
);
989 char *new_home_dir
= malloc (strlen (this->pw_dir
) + 2);
991 strcpy (new_home_dir
, this->pw_dir
);
992 strcat (new_home_dir
, "/");
993 home_dir
= new_home_dir
;
999 if (setgid (this->pw_gid
) == -1)
1002 #ifdef HAVE_INITGROUPS
1004 if (NGROUPS_MAX
> 1 && initgroups (this->pw_name
, this->pw_gid
))
1009 #if defined (HAVE_SETUID)
1010 if (setuid (this->pw_uid
))
1012 #elif defined (HAVE_SETREUID)
1013 if (setreuid (this->pw_uid
, this->pw_uid
))
1017 /* If the setuid call failed, then deny access */
1018 /* This should fix the problem on those machines with strange setups */
1019 if (getuid () != this->pw_uid
)
1022 if (strcmp (username
, "ftp") == 0)
1023 chroot (this->pw_dir
);
1031 do_rauth (int socket
)
1033 struct sockaddr_in from
;
1036 if (getpeername (0, (struct sockaddr
*) &from
, &fromlen
) < 0)
1038 from
.sin_port
= ntohs ((unsigned short) from
.sin_port
);
1040 /* Strange, this should not happend */
1041 if (from
.sin_family
!= AF_INET
)
1044 hp
= gethostbyaddr ((char *) &fromp
.sin_addr
, sizeof (struct in_addr
),
1051 do_rauth (int msock
)
1057 login_reply (int logged_in
)
1059 rpc_send (msock
, RPC_INT
, logged_in
? MC_LOGINOK
: MC_INVALID_PASS
,
1063 /* FIXME: Implement the anonymous login */
1071 rpc_get (msock
, RPC_LIMITED_STRING
, &up_dir
, RPC_LIMITED_STRING
,
1072 &username
, RPC_END
);
1074 printf ("username: %s\n", username
);
1077 logged_in
= do_rauth (msock
);
1079 login_reply (logged_in
);
1083 rpc_send (msock
, RPC_INT
, MC_NEED_PASSWORD
, RPC_END
);
1084 rpc_get (msock
, RPC_INT
, &result
, RPC_END
);
1085 if (result
== MC_QUIT
)
1087 if (result
!= MC_PASS
) {
1089 printf ("do_login: Unknown response: %d\n", result
);
1092 rpc_get (msock
, RPC_LIMITED_STRING
, &password
, RPC_END
);
1093 logged_in
= do_auth (username
, password
);
1095 login_reply (logged_in
);
1100 /* {{{ Server and dispatching functions */
1102 /* This structure must be kept in synch with mcfs.h enums */
1104 static const struct _command
{
1105 const char *command
;
1106 void (*callback
) (void);
1110 "close", do_close
}, {
1112 "write", do_write
}, {
1113 "opendir", do_opendir
}, {
1114 "readdir", do_readdir
}, {
1115 "closedir", do_closedir
}, {
1116 "stat ", do_stat
}, {
1117 "lstat ", do_lstat
}, {
1118 "fstat", do_fstat
}, {
1119 "chmod", do_chmod
}, {
1120 "chown", do_chown
}, {
1121 "readlink ", do_readlink
}, {
1122 "unlink", do_unlink
}, {
1123 "rename", do_rename
}, {
1124 "chdir ", do_chdir
}, {
1125 "lseek", do_lseek
}, {
1126 "rmdir", do_rmdir
}, {
1127 "symlink", do_symlink
}, {
1128 "mknod", do_mknod
}, {
1129 "mkdir", do_mkdir
}, {
1131 "gethome", do_gethome
}, {
1132 "getupdir", do_getupdir
}, {
1133 "login", do_login
}, {
1135 "utime", do_utime
}};
1137 static int ncommands
= sizeof (commands
) / sizeof (struct _command
);
1140 exec_command (int command
)
1142 if (command
< 0 || command
>= ncommands
1143 || commands
[command
].command
== 0) {
1144 fprintf (stderr
, "Got unknown command: %d\n", command
);
1148 printf ("Command: %s\n", commands
[command
].command
);
1149 (*commands
[command
].callback
) ();
1153 check_version (void)
1157 rpc_get (msock
, RPC_INT
, &version
, RPC_END
);
1158 if (version
>= 1 && version
<= RPC_PROGVER
)
1159 rpc_send (msock
, RPC_INT
, MC_VERSION_OK
, RPC_END
);
1161 rpc_send (msock
, RPC_INT
, MC_VERSION_MISMATCH
, RPC_END
);
1163 clnt_version
= version
;
1166 /* This routine is called by rpc_get/rpc_send when the connection is closed */
1168 tcp_invalidate_socket (int sock
)
1171 printf ("Connection closed\n");
1185 if (rpc_get (sock
, RPC_INT
, &command
, RPC_END
)
1186 && (logged_in
|| command
== MC_LOGIN
))
1187 exec_command (command
);
1188 } while (!quit_server
);
1193 /* {{{ Net support code */
1196 get_client (int portnum
)
1198 int sock
, newsocket
;
1199 unsigned int clilen
;
1200 struct sockaddr_in client_address
, server_address
;
1203 if ((sock
= socket (AF_INET
, SOCK_STREAM
, 0)) < 0)
1204 return "Cannot create socket";
1206 /* Use this to debug: */
1208 (sock
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &yes
, sizeof (yes
)) < 0)
1209 return "setsockopt failed";
1211 memset ((char *) &server_address
, 0, sizeof (server_address
));
1212 server_address
.sin_family
= AF_INET
;
1213 server_address
.sin_addr
.s_addr
= htonl (INADDR_ANY
);
1214 server_address
.sin_port
= htons (portnum
);
1217 (sock
, (struct sockaddr
*) &server_address
,
1218 sizeof (server_address
)) < 0)
1219 return "Cannot bind";
1226 clilen
= sizeof (client_address
);
1228 accept (sock
, (struct sockaddr
*) &client_address
, &clilen
);
1230 if (isDaemon
&& (child
= fork ())) {
1234 waitpid (child
, &status
, 0);
1238 if (isDaemon
&& fork ())
1247 #ifdef HAVE_PMAP_SET
1249 signal_int_handler (int sig
)
1253 pmap_unset (RPC_PROGNUM
, RPC_PROGVER
);
1257 #ifndef IPPORT_RESERVED
1258 #define IPPORT_RESERVED 1024
1262 get_port_number (void)
1266 #ifdef HAVE_RRESVPORT
1267 int start_port
= IPPORT_RESERVED
;
1269 port
= rresvport (&start_port
);
1271 if (geteuid () == 0) {
1273 "Cannot bind the server on a reserved port\n");
1274 DO_QUIT_NONVOID (-1);
1282 port
= mcserver_port
;
1288 register_port (int portnum
, int abort_if_fail
)
1290 #ifdef HAVE_PMAP_SET
1291 /* Register our service with the portmapper */
1292 /* protocol: pmap_set (prognum, versnum, protocol, portp) */
1294 if (pmap_set (RPC_PROGNUM
, RPC_PROGVER
, IPPROTO_TCP
, portnum
))
1295 signal (SIGINT
, signal_int_handler
);
1297 fprintf (stderr
, "Cannot register service with portmapper\n");
1302 if (abort_if_fail
) {
1304 "This system lacks port registration, try using the -p\n"
1305 "flag to force installation at a given port");
1313 main (int argc
, char *argv
[])
1318 while ((c
= getopt (argc
, argv
, "fdiqp:v")) != -1) {
1338 portnum
= atoi (optarg
);
1351 "Usage is: mcserv [options] [-p portnum]\n\n"
1352 "options are:\n" "-d become a daemon (sets -q)\n"
1354 /* "-r use rhost based authentication\n" */
1356 "-f force ftp authentication\n"
1359 "-p to specify a port number to listen\n");
1365 if (isDaemon
&& fork ())
1369 portnum
= get_port_number ();
1371 if (portnum
!= -1) {
1372 register_port (portnum
, 0);
1374 printf ("Using port %d\n", portnum
);
1375 if ((result
= get_client (portnum
)))
1377 #ifdef HAVE_PMAP_SET
1379 pmap_unset (RPC_PROGNUM
, RPC_PROGVER
);
1385 /* FIXME: This function should not be used in mcserv */
1387 vfs_die (const char *m
)