vsftpd 2.3.5
[tomato.git] / release / src-rt-6.x.4708 / router / vsftpd / sysdeputil.c
blob9dc8a5e7d927f517857caf23161843c02f6691b1
1 /*
2 * Part of Very Secure FTPd
3 * Licence: GPL v2
4 * Author: Chris Evans
5 * sysdeputil.c
7 * Highly system dependent utilities - e.g. authentication, capabilities.
8 */
10 #include "sysdeputil.h"
11 #include "str.h"
12 #include "sysutil.h"
13 #include "utility.h"
14 #include "secbuf.h"
15 #include "defs.h"
16 #include "tunables.h"
17 #include "builddefs.h"
19 /* For Linux, this adds nothing :-) */
20 #include "port/porting_junk.h"
22 #if (defined(__FreeBSD__) && __FreeBSD__ >= 3)
23 #define _FILE_OFFSET_BITS 64
24 #define _LARGEFILE_SOURCE 1
25 #define _LARGEFILE64_SOURCE 1
26 #endif
28 /* For INT_MAX */
29 #include <limits.h>
31 /* For fd passing */
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 /* For FreeBSD */
35 #include <sys/param.h>
36 #include <sys/uio.h>
38 #include <sys/prctl.h>
39 #include <signal.h>
41 /* Configuration.. here are the possibilities */
42 #undef VSF_SYSDEP_HAVE_CAPABILITIES
43 #undef VSF_SYSDEP_HAVE_SETKEEPCAPS
44 #undef VSF_SYSDEP_HAVE_SETPDEATHSIG
45 #undef VSF_SYSDEP_HAVE_LINUX_SENDFILE
46 #undef VSF_SYSDEP_HAVE_FREEBSD_SENDFILE
47 #undef VSF_SYSDEP_HAVE_HPUX_SENDFILE
48 #undef VSF_SYSDEP_HAVE_AIX_SENDFILE
49 #undef VSF_SYSDEP_HAVE_SETPROCTITLE
50 #undef VSF_SYSDEP_TRY_LINUX_SETPROCTITLE_HACK
51 #undef VSF_SYSDEP_HAVE_HPUX_SETPROCTITLE
52 #undef VSF_SYSDEP_HAVE_MAP_ANON
53 #undef VSF_SYSDEP_NEED_OLD_FD_PASSING
54 #undef VSF_SYSDEP_HAVE_LINUX_CLONE
55 #ifdef VSF_BUILD_PAM
56 #define VSF_SYSDEP_HAVE_PAM
57 #endif
58 #define VSF_SYSDEP_HAVE_SHADOW
59 #define VSF_SYSDEP_HAVE_USERSHELL
60 #define VSF_SYSDEP_HAVE_LIBCAP
61 #define VSF_SYSDEP_HAVE_UTMPX
63 #define __USE_GNU
64 #include <utmpx.h>
66 /* BEGIN config */
67 #if defined(__linux__)
68 #include <errno.h>
69 #include <syscall.h>
70 #define VSF_SYSDEP_HAVE_LINUX_CLONE
71 #include <sched.h>
72 #ifndef CLONE_NEWPID
73 #define CLONE_NEWPID 0x20000000
74 #endif
75 #ifndef CLONE_NEWIPC
76 #define CLONE_NEWIPC 0x08000000
77 #endif
78 #ifndef CLONE_NEWNET
79 #define CLONE_NEWNET 0x40000000
80 #endif
81 #include <linux/unistd.h>
82 #include <errno.h>
83 #include <syscall.h>
84 #endif
86 #if defined(__linux__) && !defined(__ia64__) && !defined(__s390__)
87 #define VSF_SYSDEP_TRY_LINUX_SETPROCTITLE_HACK
88 #include <linux/version.h>
89 #if defined(LINUX_VERSION_CODE) && defined(KERNEL_VERSION)
90 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0))
91 #define VSF_SYSDEP_HAVE_CAPABILITIES
92 #define VSF_SYSDEP_HAVE_LINUX_SENDFILE
93 #ifdef PR_SET_KEEPCAPS
94 #define VSF_SYSDEP_HAVE_SETKEEPCAPS
95 #endif
96 #ifdef PR_SET_PDEATHSIG
97 #define VSF_SYSDEP_HAVE_SETPDEATHSIG
98 #endif
99 #endif
100 #endif
101 #endif
103 #if (defined(__FreeBSD__) && __FreeBSD__ >= 3)
104 #define VSF_SYSDEP_HAVE_FREEBSD_SENDFILE
105 #define VSF_SYSDEP_HAVE_SETPROCTITLE
106 #endif
108 #if defined(__NetBSD__)
109 #include <stdlib.h>
110 #define VSF_SYSDEP_HAVE_SETPROCTITLE
111 #include <sys/param.h>
112 #if __NetBSD_Version__ >= 106070000
113 #define WTMPX_FILE _PATH_WTMPX
114 #else
115 #undef VSF_SYSDEP_HAVE_UTMPX
116 #endif
117 #endif
119 #ifdef __hpux
120 #include <sys/socket.h>
121 #ifdef SF_DISCONNECT
122 #define VSF_SYSDEP_HAVE_HPUX_SENDFILE
123 #endif
124 #include <sys/param.h>
125 #include <sys/pstat.h>
126 #ifdef PSTAT_SETCMD
127 #define VSF_SYSDEP_HAVE_HPUX_SETPROCTITLE
128 #endif
129 #undef VSF_SYSDEP_HAVE_UTMPX
130 #endif
132 #include <unistd.h>
133 #include <sys/mman.h>
134 #ifdef MAP_ANON
135 #define VSF_SYSDEP_HAVE_MAP_ANON
136 #endif
138 #ifdef __sgi
139 #undef VSF_SYSDEP_HAVE_USERSHELL
140 #undef VSF_SYSDEP_HAVE_LIBCAP
141 #endif
143 #ifdef _AIX
144 #undef VSF_SYSDEP_HAVE_USERSHELL
145 #undef VSF_SYSDEP_HAVE_LIBCAP
146 #undef VSF_SYSDEP_HAVE_UTMPX
147 #undef VSF_SYSDEP_HAVE_PAM
148 #undef VSF_SYSDEP_HAVE_SHADOW
149 #undef VSF_SYSDEP_HAVE_SETPROCTITLE
150 #define VSF_SYSDEP_HAVE_AIX_SENDFILE
151 #define VSF_SYSDEP_TRY_LINUX_SETPROCTITLE_HACK
152 #define VSF_SYSDEP_HAVE_MAP_ANON
153 #endif
155 #ifdef __osf__
156 #undef VSF_SYSDEP_HAVE_USERSHELL
157 #endif
159 #if (defined(__sgi) || defined(__hpux) || defined(__osf__))
160 #define VSF_SYSDEP_NEED_OLD_FD_PASSING
161 #endif
163 #ifdef __sun
164 #define VSF_SYSDEP_HAVE_SOLARIS_SENDFILE
165 #endif
166 /* END config */
168 /* PAM support - we include our own dummy version if the system lacks this */
169 #include <security/pam_appl.h>
171 /* No PAM? Try getspnam() with a getpwnam() fallback */
172 #ifndef VSF_SYSDEP_HAVE_PAM
173 /* This may hit our own "dummy" include and undef VSF_SYSDEP_HAVE_SHADOW */
174 #include <shadow.h>
175 #include <pwd.h>
176 #include <unistd.h>
177 #include <crypt.h>
178 #endif
180 /* Prefer libcap based capabilities over raw syscall capabilities */
181 #include <sys/capability.h>
183 #if defined(VSF_SYSDEP_HAVE_CAPABILITIES) && !defined(VSF_SYSDEP_HAVE_LIBCAP)
184 #include <linux/unistd.h>
185 #include <linux/capability.h>
186 #include <errno.h>
187 #include <syscall.h>
188 int capset(cap_user_header_t header, const cap_user_data_t data)
190 return syscall(__NR_capset, header, data);
192 /* Gross HACK to avoid warnings - linux headers overlap glibc headers */
193 #undef __NFDBITS
194 #undef __FDMASK
195 #endif /* VSF_SYSDEP_HAVE_CAPABILITIES */
197 #if defined(VSF_SYSDEP_HAVE_LINUX_SENDFILE) || \
198 defined(VSF_SYSDEP_HAVE_SOLARIS_SENDFILE)
199 #include <sys/sendfile.h>
200 #elif defined(VSF_SYSDEP_HAVE_FREEBSD_SENDFILE)
201 #include <sys/types.h>
202 #include <sys/socket.h>
203 #elif defined(VSF_SYSDEP_HAVE_HPUX_SENDFILE)
204 #include <sys/socket.h>
205 #else /* VSF_SYSDEP_HAVE_LINUX_SENDFILE */
206 #include <unistd.h>
207 #endif /* VSF_SYSDEP_HAVE_LINUX_SENDFILE */
209 #ifdef VSF_SYSDEP_HAVE_SETPROCTITLE
210 #include <sys/types.h>
211 #include <unistd.h>
212 #endif
214 #ifdef VSF_SYSDEP_TRY_LINUX_SETPROCTITLE_HACK
215 extern char** environ;
216 static unsigned int s_proctitle_space = 0;
217 static int s_proctitle_inited = 0;
218 static char* s_p_proctitle = 0;
219 #endif
221 #ifndef VSF_SYSDEP_HAVE_MAP_ANON
222 #include <sys/types.h>
223 #include <sys/stat.h>
224 #include <fcntl.h>
225 static int s_zero_fd = -1;
226 #endif
228 /* File private functions/variables */
229 static int do_sendfile(const int out_fd, const int in_fd,
230 unsigned int num_send, filesize_t start_pos);
231 static void vsf_sysutil_setproctitle_internal(const char* p_text);
232 static struct mystr s_proctitle_prefix_str;
234 /* These two aren't static to avoid OpenBSD build warnings. */
235 void vsf_insert_uwtmp(const struct mystr* p_user_str,
236 const struct mystr* p_host_str);
237 void vsf_remove_uwtmp(void);
239 #ifndef VSF_SYSDEP_HAVE_PAM
241 vsf_sysdep_check_auth(struct mystr* p_user_str,
242 const struct mystr* p_pass_str,
243 const struct mystr* p_remote_host)
245 const char* p_crypted;
246 const struct passwd* p_pwd = getpwnam(str_getbuf(p_user_str));
247 (void) p_remote_host;
248 if (p_pwd == NULL)
250 return 0;
252 #ifdef VSF_SYSDEP_HAVE_USERSHELL
253 if (tunable_check_shell)
255 const char* p_shell;
256 while ((p_shell = getusershell()) != NULL)
258 if (!vsf_sysutil_strcmp(p_shell, p_pwd->pw_shell))
260 break;
263 endusershell();
264 if (p_shell == NULL)
266 return 0;
269 #endif
270 #ifdef VSF_SYSDEP_HAVE_SHADOW
272 const struct spwd* p_spwd = getspnam(str_getbuf(p_user_str));
273 if (p_spwd != NULL)
275 long curr_time = vsf_sysutil_get_time_sec();
276 int days;
277 days = curr_time / (60 * 60 * 24);
278 if (p_spwd->sp_expire > 0 && p_spwd->sp_expire < days)
280 return 0;
282 if (p_spwd->sp_lstchg > 0 && p_spwd->sp_max > 0 &&
283 p_spwd->sp_lstchg + p_spwd->sp_max < days)
285 return 0;
287 p_crypted = crypt(str_getbuf(p_pass_str), p_spwd->sp_pwdp);
288 if (!vsf_sysutil_strcmp(p_crypted, p_spwd->sp_pwdp))
290 return 1;
294 #endif /* VSF_SYSDEP_HAVE_SHADOW */
295 p_crypted = crypt(str_getbuf(p_pass_str), p_pwd->pw_passwd);
296 if (!vsf_sysutil_strcmp(p_crypted, p_pwd->pw_passwd))
298 return 1;
300 return 0;
303 #else /* VSF_SYSDEP_HAVE_PAM */
305 #if (defined(__sun) || defined(__hpux)) && \
306 !defined(LINUX_PAM) && !defined(_OPENPAM)
307 /* Sun's PAM doesn't use const here, while Linux-PAM and OpenPAM do */
308 #define lo_const
309 #else
310 #define lo_const const
311 #endif
312 typedef lo_const void* pam_item_t;
314 static pam_handle_t* s_pamh;
315 static struct mystr s_pword_str;
316 static int pam_conv_func(int nmsg, const struct pam_message** p_msg,
317 struct pam_response** p_reply, void* p_addata);
318 static void vsf_auth_shutdown(void);
321 vsf_sysdep_check_auth(struct mystr* p_user_str,
322 const struct mystr* p_pass_str,
323 const struct mystr* p_remote_host)
325 int retval;
326 pam_item_t item;
327 const char* pam_user_name = 0;
328 struct pam_conv the_conv =
330 &pam_conv_func,
333 if (s_pamh != 0)
335 bug("vsf_sysdep_check_auth");
337 str_copy(&s_pword_str, p_pass_str);
338 retval = pam_start(tunable_pam_service_name,
339 str_getbuf(p_user_str), &the_conv, &s_pamh);
340 if (retval != PAM_SUCCESS)
342 s_pamh = 0;
343 return 0;
345 #ifdef PAM_RHOST
346 retval = pam_set_item(s_pamh, PAM_RHOST, str_getbuf(p_remote_host));
347 if (retval != PAM_SUCCESS)
349 (void) pam_end(s_pamh, retval);
350 s_pamh = 0;
351 return 0;
353 #endif
354 #ifdef PAM_TTY
355 retval = pam_set_item(s_pamh, PAM_TTY, "ftp");
356 if (retval != PAM_SUCCESS)
358 (void) pam_end(s_pamh, retval);
359 s_pamh = 0;
360 return 0;
362 #endif
363 #ifdef PAM_RUSER
364 retval = pam_set_item(s_pamh, PAM_RUSER, str_getbuf(p_user_str));
365 if (retval != PAM_SUCCESS)
367 (void) pam_end(s_pamh, retval);
368 s_pamh = 0;
369 return 0;
371 #endif
372 retval = pam_authenticate(s_pamh, 0);
373 if (retval != PAM_SUCCESS)
375 (void) pam_end(s_pamh, retval);
376 s_pamh = 0;
377 return 0;
379 #ifdef PAM_USER
380 retval = pam_get_item(s_pamh, PAM_USER, &item);
381 if (retval != PAM_SUCCESS)
383 (void) pam_end(s_pamh, retval);
384 s_pamh = 0;
385 return 0;
387 pam_user_name = item;
388 str_alloc_text(p_user_str, pam_user_name);
389 #endif
390 retval = pam_acct_mgmt(s_pamh, 0);
391 if (retval != PAM_SUCCESS)
393 (void) pam_end(s_pamh, retval);
394 s_pamh = 0;
395 return 0;
397 retval = pam_setcred(s_pamh, PAM_ESTABLISH_CRED);
398 if (retval != PAM_SUCCESS)
400 (void) pam_end(s_pamh, retval);
401 s_pamh = 0;
402 return 0;
404 if (!tunable_session_support)
406 /* You're in already! */
407 (void) pam_end(s_pamh, retval);
408 s_pamh = 0;
409 return 1;
411 /* Must do this BEFORE opening a session for pam_limits to count us */
412 vsf_insert_uwtmp(p_user_str, p_remote_host);
413 retval = pam_open_session(s_pamh, 0);
414 if (retval != PAM_SUCCESS)
416 vsf_remove_uwtmp();
417 (void) pam_setcred(s_pamh, PAM_DELETE_CRED);
418 (void) pam_end(s_pamh, retval);
419 s_pamh = 0;
420 return 0;
422 /* We MUST ensure the PAM session, utmp, wtmp etc. are cleaned up, however
423 * we exit.
425 vsf_sysutil_set_exit_func(vsf_auth_shutdown);
426 /* You're in dude */
427 return 1;
430 static void
431 vsf_auth_shutdown(void)
433 if (s_pamh == 0)
435 bug("vsf_auth_shutdown");
437 (void) pam_close_session(s_pamh, 0);
438 (void) pam_setcred(s_pamh, PAM_DELETE_CRED);
439 (void) pam_end(s_pamh, PAM_SUCCESS);
440 s_pamh = 0;
441 vsf_remove_uwtmp();
444 static int
445 pam_conv_func(int nmsg, const struct pam_message** p_msg,
446 struct pam_response** p_reply, void* p_addata)
448 int i;
449 struct pam_response* p_resps = 0;
450 (void) p_addata;
451 if (nmsg < 0)
453 bug("dodgy nmsg in pam_conv_func");
455 p_resps = vsf_sysutil_malloc(sizeof(struct pam_response) * nmsg);
456 for (i=0; i<nmsg; i++)
458 switch (p_msg[i]->msg_style)
460 case PAM_PROMPT_ECHO_OFF:
461 p_resps[i].resp_retcode = PAM_SUCCESS;
462 p_resps[i].resp = (char*) str_strdup(&s_pword_str);
463 break;
464 case PAM_TEXT_INFO:
465 case PAM_ERROR_MSG:
466 p_resps[i].resp_retcode = PAM_SUCCESS;
467 p_resps[i].resp = 0;
468 break;
469 case PAM_PROMPT_ECHO_ON:
470 default:
471 vsf_sysutil_free(p_resps);
472 return PAM_CONV_ERR;
473 break;
476 *p_reply = p_resps;
477 return PAM_SUCCESS;
480 #endif /* VSF_SYSDEP_HAVE_PAM */
482 /* Capabilities support (or lack thereof) */
483 void
484 vsf_sysdep_keep_capabilities(void)
486 if (!vsf_sysdep_has_capabilities_as_non_root())
488 bug("asked to keep capabilities, but no support exists");
490 #ifdef VSF_SYSDEP_HAVE_SETKEEPCAPS
492 int retval = prctl(PR_SET_KEEPCAPS, 1);
493 if (vsf_sysutil_retval_is_error(retval))
495 die("prctl");
498 #endif /* VSF_SYSDEP_HAVE_SETKEEPCAPS */
500 #if !defined(VSF_SYSDEP_HAVE_CAPABILITIES) && !defined(VSF_SYSDEP_HAVE_LIBCAP)
503 vsf_sysdep_has_capabilities(void)
505 return 0;
509 vsf_sysdep_has_capabilities_as_non_root(void)
511 return 0;
514 void
515 vsf_sysdep_adopt_capabilities(unsigned int caps)
517 (void) caps;
518 bug("asked to adopt capabilities, but no support exists");
521 #else /* VSF_SYSDEP_HAVE_CAPABILITIES || VSF_SYSDEP_HAVE_LIBCAP */
523 static int do_checkcap(void);
526 vsf_sysdep_has_capabilities_as_non_root(void)
528 static int s_prctl_checked;
529 static int s_runtime_prctl_works;
530 if (!s_prctl_checked)
532 #ifdef VSF_SYSDEP_HAVE_SETKEEPCAPS
533 /* Clarity: note embedded call to prctl() syscall */
534 if (!vsf_sysutil_retval_is_error(prctl(PR_SET_KEEPCAPS, 0)))
536 s_runtime_prctl_works = 1;
538 #endif /* VSF_SYSDEP_HAVE_SETKEEPCAPS */
539 s_prctl_checked = 1;
541 return s_runtime_prctl_works;
545 vsf_sysdep_has_capabilities(void)
547 /* Even though compiled with capabilities, the runtime system may lack them.
548 * Also, RH7.0 kernel headers advertise a 2.4.0 box, but on a 2.2.x kernel!
550 static int s_caps_checked;
551 static int s_runtime_has_caps;
552 if (!s_caps_checked)
554 s_runtime_has_caps = do_checkcap();
555 s_caps_checked = 1;
557 return s_runtime_has_caps;
560 #ifndef VSF_SYSDEP_HAVE_LIBCAP
561 static int
562 do_checkcap(void)
564 /* EFAULT (EINVAL if page 0 mapped) vs. ENOSYS */
565 int retval = capset(0, 0);
566 if (!vsf_sysutil_retval_is_error(retval) ||
567 vsf_sysutil_get_error() != kVSFSysUtilErrNOSYS)
569 return 1;
571 return 0;
574 void
575 vsf_sysdep_adopt_capabilities(unsigned int caps)
577 /* n.b. yes I know I should be using libcap!! */
578 int retval;
579 struct __user_cap_header_struct cap_head;
580 struct __user_cap_data_struct cap_data;
581 __u32 cap_mask = 0;
582 if (!caps)
584 bug("asked to adopt no capabilities");
586 vsf_sysutil_memclr(&cap_head, sizeof(cap_head));
587 vsf_sysutil_memclr(&cap_data, sizeof(cap_data));
588 cap_head.version = _LINUX_CAPABILITY_VERSION;
589 cap_head.pid = 0;
590 if (caps & kCapabilityCAP_CHOWN)
592 cap_mask |= (1 << CAP_CHOWN);
594 if (caps & kCapabilityCAP_NET_BIND_SERVICE)
596 cap_mask |= (1 << CAP_NET_BIND_SERVICE);
598 cap_data.effective = cap_data.permitted = cap_mask;
599 cap_data.inheritable = 0;
600 retval = capset(&cap_head, &cap_data);
601 if (retval != 0)
603 die("capset");
607 #else /* VSF_SYSDEP_HAVE_LIBCAP */
608 static int
609 do_checkcap(void)
611 cap_t current_caps = cap_get_proc();
612 cap_free(current_caps);
613 if (current_caps != NULL)
615 return 1;
617 return 0;
620 void
621 vsf_sysdep_adopt_capabilities(unsigned int caps)
623 int retval;
624 cap_value_t cap_value;
625 cap_t adopt_caps = cap_init();
626 if (caps & kCapabilityCAP_CHOWN)
628 cap_value = CAP_CHOWN;
629 cap_set_flag(adopt_caps, CAP_EFFECTIVE, 1, &cap_value, CAP_SET);
630 cap_set_flag(adopt_caps, CAP_PERMITTED, 1, &cap_value, CAP_SET);
632 if (caps & kCapabilityCAP_NET_BIND_SERVICE)
634 cap_value = CAP_NET_BIND_SERVICE;
635 cap_set_flag(adopt_caps, CAP_EFFECTIVE, 1, &cap_value, CAP_SET);
636 cap_set_flag(adopt_caps, CAP_PERMITTED, 1, &cap_value, CAP_SET);
638 retval = cap_set_proc(adopt_caps);
639 if (retval != 0)
641 die("cap_set_proc");
643 cap_free(adopt_caps);
646 #endif /* !VSF_SYSDEP_HAVE_LIBCAP */
647 #endif /* VSF_SYSDEP_HAVE_CAPABILITIES || VSF_SYSDEP_HAVE_LIBCAP */
650 vsf_sysutil_sendfile(const int out_fd, const int in_fd,
651 filesize_t* p_offset, filesize_t num_send,
652 unsigned int max_chunk)
654 /* Grr - why is off_t signed? */
655 if (*p_offset < 0 || num_send < 0)
657 die("invalid offset or send count in vsf_sysutil_sendfile");
659 if (max_chunk == 0)
661 max_chunk = INT_MAX;
663 while (num_send > 0)
665 int retval;
666 unsigned int send_this_time;
667 if (num_send > max_chunk)
669 send_this_time = max_chunk;
671 else
673 send_this_time = (unsigned int) num_send;
675 /* Keep input file position in line with sendfile() calls */
676 vsf_sysutil_lseek_to(in_fd, *p_offset);
677 retval = do_sendfile(out_fd, in_fd, send_this_time, *p_offset);
678 if (vsf_sysutil_retval_is_error(retval) || retval == 0)
680 return retval;
682 num_send -= retval;
683 *p_offset += retval;
685 return 0;
688 static int do_sendfile(const int out_fd, const int in_fd,
689 unsigned int num_send, filesize_t start_pos)
691 /* Probably should one day be shared with instance in ftpdataio.c */
692 static char* p_recvbuf;
693 unsigned int total_written = 0;
694 int retval;
695 enum EVSFSysUtilError error;
696 (void) start_pos;
697 (void) error;
698 #if defined(VSF_SYSDEP_HAVE_LINUX_SENDFILE) || \
699 defined(VSF_SYSDEP_HAVE_FREEBSD_SENDFILE) || \
700 defined(VSF_SYSDEP_HAVE_HPUX_SENDFILE) || \
701 defined(VSF_SYSDEP_HAVE_AIX_SENDFILE) || \
702 defined(VSF_SYSDEP_HAVE_SOLARIS_SENDFILE)
703 if (tunable_use_sendfile)
705 static int s_sendfile_checked;
706 static int s_runtime_sendfile_works;
707 if (!s_sendfile_checked || s_runtime_sendfile_works)
711 #ifdef VSF_SYSDEP_HAVE_LINUX_SENDFILE
712 retval = sendfile(out_fd, in_fd, NULL, num_send);
713 #elif defined(VSF_SYSDEP_HAVE_FREEBSD_SENDFILE)
715 /* XXX - start_pos will truncate on 32-bit machines - can we
716 * say "start from current pos"?
718 off_t written = 0;
719 retval = sendfile(in_fd, out_fd, start_pos, num_send, NULL,
720 &written, 0);
721 /* Translate to Linux-like retval */
722 if (written > 0)
724 retval = (int) written;
727 #elif defined(VSF_SYSDEP_HAVE_SOLARIS_SENDFILE)
729 size_t written = 0;
730 struct sendfilevec the_vec;
731 vsf_sysutil_memclr(&the_vec, sizeof(the_vec));
732 the_vec.sfv_fd = in_fd;
733 the_vec.sfv_off = start_pos;
734 the_vec.sfv_len = num_send;
735 retval = sendfilev(out_fd, &the_vec, 1, &written);
736 /* Translate to Linux-like retval */
737 if (written > 0)
739 retval = (int) written;
742 #elif defined(VSF_SYSDEP_HAVE_AIX_SENDFILE)
744 struct sf_parms sf_iobuf;
745 vsf_sysutil_memclr(&sf_iobuf, sizeof(sf_iobuf));
746 sf_iobuf.header_data = NULL;
747 sf_iobuf.header_length = 0;
748 sf_iobuf.trailer_data = NULL;
749 sf_iobuf.trailer_length = 0;
750 sf_iobuf.file_descriptor = in_fd;
751 sf_iobuf.file_offset = start_pos;
752 sf_iobuf.file_bytes = num_send;
754 retval = send_file((int*)&out_fd, &sf_iobuf, 0);
755 if (retval >= 0)
757 retval = sf_iobuf.bytes_sent;
760 #else /* must be VSF_SYSDEP_HAVE_HPUX_SENDFILE */
762 retval = sendfile(out_fd, in_fd, start_pos, num_send, NULL, 0);
764 #endif /* VSF_SYSDEP_HAVE_LINUX_SENDFILE */
765 error = vsf_sysutil_get_error();
766 vsf_sysutil_check_pending_actions(kVSFSysUtilIO, retval, out_fd);
768 while (vsf_sysutil_retval_is_error(retval) &&
769 error == kVSFSysUtilErrINTR);
770 if (!s_sendfile_checked)
772 s_sendfile_checked = 1;
773 if (!vsf_sysutil_retval_is_error(retval) ||
774 error != kVSFSysUtilErrNOSYS)
776 s_runtime_sendfile_works = 1;
779 if (!vsf_sysutil_retval_is_error(retval))
781 return retval;
783 if (s_runtime_sendfile_works && error != kVSFSysUtilErrINVAL &&
784 error != kVSFSysUtilErrOPNOTSUPP)
786 return retval;
788 /* Fall thru to normal implementation. We won't check again. NOTE -
789 * also falls through if sendfile() is OK but it returns EINVAL. For
790 * Linux this means the file was not page cache backed. Original
791 * complaint was trying to serve files from an NTFS filesystem!
795 #endif /* VSF_SYSDEP_HAVE_LINUX_SENDFILE || VSF_SYSDEP_HAVE_FREEBSD_SENDFILE */
796 if (p_recvbuf == 0)
798 vsf_secbuf_alloc(&p_recvbuf, VSFTP_DATA_BUFSIZE);
800 while (1)
802 unsigned int num_read;
803 unsigned int num_written;
804 unsigned int num_read_this_time = VSFTP_DATA_BUFSIZE;
805 if (num_read_this_time > num_send)
807 num_read_this_time = num_send;
809 retval = vsf_sysutil_read(in_fd, p_recvbuf, num_read_this_time);
810 if (retval < 0)
812 return retval;
814 else if (retval == 0)
816 return -1;
818 num_read = (unsigned int) retval;
819 retval = vsf_sysutil_write_loop(out_fd, p_recvbuf, num_read);
820 if (retval < 0)
822 return retval;
824 num_written = (unsigned int) retval;
825 total_written += num_written;
826 if (num_written != num_read)
828 return num_written;
830 if (num_written > num_send)
832 bug("num_written bigger than num_send in do_sendfile");
834 num_send -= num_written;
835 if (num_send == 0)
837 /* Bingo! */
838 return total_written;
843 void
844 vsf_sysutil_set_proctitle_prefix(const struct mystr* p_str)
846 str_copy(&s_proctitle_prefix_str, p_str);
849 /* This delegation is common to all setproctitle() implementations */
850 void
851 vsf_sysutil_setproctitle_str(const struct mystr* p_str)
853 vsf_sysutil_setproctitle(str_getbuf(p_str));
856 void
857 vsf_sysutil_setproctitle(const char* p_text)
859 struct mystr proctitle_str = INIT_MYSTR;
860 str_copy(&proctitle_str, &s_proctitle_prefix_str);
861 if (!str_isempty(&proctitle_str))
863 str_append_text(&proctitle_str, ": ");
865 str_append_text(&proctitle_str, p_text);
866 vsf_sysutil_setproctitle_internal(str_getbuf(&proctitle_str));
867 str_free(&proctitle_str);
870 #ifdef VSF_SYSDEP_HAVE_SETPROCTITLE
871 void
872 vsf_sysutil_setproctitle_init(int argc, const char* argv[])
874 (void) argc;
875 (void) argv;
878 void
879 vsf_sysutil_setproctitle_internal(const char* p_buf)
881 setproctitle("%s", p_buf);
883 #elif defined(VSF_SYSDEP_HAVE_HPUX_SETPROCTITLE)
884 void
885 vsf_sysutil_setproctitle_init(int argc, const char* argv[])
887 (void) argc;
888 (void) argv;
891 void
892 vsf_sysutil_setproctitle_internal(const char* p_buf)
894 struct mystr proctitle_str = INIT_MYSTR;
895 union pstun p;
896 str_alloc_text(&proctitle_str, "vsftpd: ");
897 str_append_text(&proctitle_str, p_buf);
898 p.pst_command = str_getbuf(&proctitle_str);
899 pstat(PSTAT_SETCMD, p, 0, 0, 0);
900 str_free(&proctitle_str);
902 #elif defined(VSF_SYSDEP_TRY_LINUX_SETPROCTITLE_HACK)
903 void
904 vsf_sysutil_setproctitle_init(int argc, const char* argv[])
906 int i;
907 char** p_env = environ;
908 if (s_proctitle_inited)
910 bug("vsf_sysutil_setproctitle_init called twice");
912 s_proctitle_inited = 1;
913 if (argv[0] == 0)
915 die("no argv[0] in vsf_sysutil_setproctitle_init");
917 for (i=0; i<argc; i++)
919 s_proctitle_space += vsf_sysutil_strlen(argv[i]) + 1;
920 if (i > 0)
922 argv[i] = 0;
925 while (*p_env != 0)
927 s_proctitle_space += vsf_sysutil_strlen(*p_env) + 1;
928 p_env++;
930 /* Oops :-) */
931 environ = 0;
932 s_p_proctitle = (char*) argv[0];
933 vsf_sysutil_memclr(s_p_proctitle, s_proctitle_space);
936 void
937 vsf_sysutil_setproctitle_internal(const char* p_buf)
939 struct mystr proctitle_str = INIT_MYSTR;
940 unsigned int to_copy;
941 if (!s_proctitle_inited)
943 bug("vsf_sysutil_setproctitle: not initialized");
945 vsf_sysutil_memclr(s_p_proctitle, s_proctitle_space);
946 if (s_proctitle_space < 32)
948 return;
950 str_alloc_text(&proctitle_str, "vsftpd: ");
951 str_append_text(&proctitle_str, p_buf);
952 to_copy = str_getlen(&proctitle_str);
953 if (to_copy > s_proctitle_space - 1)
955 to_copy = s_proctitle_space - 1;
957 vsf_sysutil_memcpy(s_p_proctitle, str_getbuf(&proctitle_str), to_copy);
958 str_free(&proctitle_str);
959 s_p_proctitle[to_copy] = '\0';
961 #else /* VSF_SYSDEP_HAVE_SETPROCTITLE */
962 void
963 vsf_sysutil_setproctitle_init(int argc, const char* argv[])
965 (void) argc;
966 (void) argv;
969 void
970 vsf_sysutil_setproctitle_internal(const char* p_buf)
972 (void) p_buf;
974 #endif /* VSF_SYSDEP_HAVE_SETPROCTITLE */
976 #ifdef VSF_SYSDEP_HAVE_MAP_ANON
977 void
978 vsf_sysutil_map_anon_pages_init(void)
982 void*
983 vsf_sysutil_map_anon_pages(unsigned int length)
985 char* retval = mmap(0, length, PROT_READ | PROT_WRITE,
986 MAP_PRIVATE | MAP_ANON, -1, 0);
987 if (retval == MAP_FAILED)
989 die("mmap");
991 return retval;
993 #else /* VSF_SYSDEP_HAVE_MAP_ANON */
994 void
995 vsf_sysutil_map_anon_pages_init(void)
997 if (s_zero_fd != -1)
999 bug("vsf_sysutil_map_anon_pages_init called twice");
1001 s_zero_fd = open("/dev/zero", O_RDWR);
1002 if (s_zero_fd < 0)
1004 die("could not open /dev/zero");
1008 void*
1009 vsf_sysutil_map_anon_pages(unsigned int length)
1011 char* retval = mmap(0, length, PROT_READ | PROT_WRITE,
1012 MAP_PRIVATE, s_zero_fd, 0);
1013 if (retval == MAP_FAILED)
1015 die("mmap");
1017 return retval;
1019 #endif /* VSF_SYSDEP_HAVE_MAP_ANON */
1021 #ifndef VSF_SYSDEP_NEED_OLD_FD_PASSING
1023 void
1024 vsf_sysutil_send_fd(int sock_fd, int send_fd)
1026 int retval;
1027 struct msghdr msg;
1028 struct cmsghdr* p_cmsg;
1029 struct iovec vec;
1030 char cmsgbuf[CMSG_SPACE(sizeof(send_fd))];
1031 int* p_fds;
1032 char sendchar = 0;
1033 msg.msg_control = cmsgbuf;
1034 msg.msg_controllen = sizeof(cmsgbuf);
1035 p_cmsg = CMSG_FIRSTHDR(&msg);
1036 p_cmsg->cmsg_level = SOL_SOCKET;
1037 p_cmsg->cmsg_type = SCM_RIGHTS;
1038 p_cmsg->cmsg_len = CMSG_LEN(sizeof(send_fd));
1039 p_fds = (int*)CMSG_DATA(p_cmsg);
1040 *p_fds = send_fd;
1041 msg.msg_controllen = p_cmsg->cmsg_len;
1042 msg.msg_name = NULL;
1043 msg.msg_namelen = 0;
1044 msg.msg_iov = &vec;
1045 msg.msg_iovlen = 1;
1046 msg.msg_flags = 0;
1047 /* "To pass file descriptors or credentials you need to send/read at
1048 * least on byte" (man 7 unix)
1050 vec.iov_base = &sendchar;
1051 vec.iov_len = sizeof(sendchar);
1052 retval = sendmsg(sock_fd, &msg, 0);
1053 if (retval != 1)
1055 die("sendmsg");
1060 vsf_sysutil_recv_fd(const int sock_fd)
1062 int retval;
1063 struct msghdr msg;
1064 char recvchar;
1065 struct iovec vec;
1066 int recv_fd;
1067 char cmsgbuf[CMSG_SPACE(sizeof(recv_fd))];
1068 struct cmsghdr* p_cmsg;
1069 int* p_fd;
1070 vec.iov_base = &recvchar;
1071 vec.iov_len = sizeof(recvchar);
1072 msg.msg_name = NULL;
1073 msg.msg_namelen = 0;
1074 msg.msg_iov = &vec;
1075 msg.msg_iovlen = 1;
1076 msg.msg_control = cmsgbuf;
1077 msg.msg_controllen = sizeof(cmsgbuf);
1078 msg.msg_flags = 0;
1079 /* In case something goes wrong, set the fd to -1 before the syscall */
1080 p_fd = (int*)CMSG_DATA(CMSG_FIRSTHDR(&msg));
1081 *p_fd = -1;
1082 retval = recvmsg(sock_fd, &msg, 0);
1083 if (retval != 1)
1085 die("recvmsg");
1087 p_cmsg = CMSG_FIRSTHDR(&msg);
1088 if (p_cmsg == NULL)
1090 die("no passed fd");
1092 /* We used to verify the returned cmsg_level, cmsg_type and cmsg_len here,
1093 * but Linux 2.0 totally uselessly fails to fill these in.
1095 p_fd = (int*)CMSG_DATA(p_cmsg);
1096 recv_fd = *p_fd;
1097 if (recv_fd == -1)
1099 die("no passed fd");
1101 return recv_fd;
1104 #else /* !VSF_SYSDEP_NEED_OLD_FD_PASSING */
1106 void
1107 vsf_sysutil_send_fd(int sock_fd, int send_fd)
1109 int retval;
1110 char send_char = 0;
1111 struct msghdr msg;
1112 struct iovec vec;
1113 vec.iov_base = &send_char;
1114 vec.iov_len = 1;
1115 msg.msg_name = NULL;
1116 msg.msg_namelen = 0;
1117 msg.msg_iov = &vec;
1118 msg.msg_iovlen = 1;
1119 msg.msg_accrights = (caddr_t) &send_fd;
1120 msg.msg_accrightslen = sizeof(send_fd);
1121 retval = sendmsg(sock_fd, &msg, 0);
1122 if (retval != 1)
1124 die("sendmsg");
1129 vsf_sysutil_recv_fd(int sock_fd)
1131 int retval;
1132 struct msghdr msg;
1133 struct iovec vec;
1134 char recv_char;
1135 int recv_fd = -1;
1136 vec.iov_base = &recv_char;
1137 vec.iov_len = 1;
1138 msg.msg_name = NULL;
1139 msg.msg_namelen = 0;
1140 msg.msg_iov = &vec;
1141 msg.msg_iovlen = 1;
1142 msg.msg_accrights = (caddr_t) &recv_fd;
1143 msg.msg_accrightslen = sizeof(recv_fd);
1144 retval = recvmsg(sock_fd, &msg, 0);
1145 if (retval != 1)
1147 die("recvmsg");
1149 if (recv_fd == -1)
1151 die("no passed fd");
1153 return recv_fd;
1156 #endif /* !VSF_SYSDEP_NEED_OLD_FD_PASSING */
1158 #ifndef VSF_SYSDEP_HAVE_UTMPX
1160 void
1161 vsf_insert_uwtmp(const struct mystr* p_user_str,
1162 const struct mystr* p_host_str)
1164 (void) p_user_str;
1165 (void) p_host_str;
1168 void
1169 vsf_remove_uwtmp(void)
1173 #else /* !VSF_SYSDEP_HAVE_UTMPX */
1175 /* IMHO, the pam_unix module REALLY should be doing this in its SM component */
1176 /* Statics */
1177 static int s_uwtmp_inserted;
1178 static struct utmpx s_utent;
1180 void
1181 vsf_insert_uwtmp(const struct mystr* p_user_str,
1182 const struct mystr* p_host_str)
1184 if (sizeof(s_utent.ut_line) < 16)
1186 return;
1188 if (s_uwtmp_inserted)
1190 bug("vsf_insert_uwtmp");
1193 struct mystr line_str = INIT_MYSTR;
1194 str_alloc_text(&line_str, "vsftpd:");
1195 str_append_ulong(&line_str, vsf_sysutil_getpid());
1196 if (str_getlen(&line_str) >= sizeof(s_utent.ut_line))
1198 str_free(&line_str);
1199 return;
1201 vsf_sysutil_strcpy(s_utent.ut_line, str_getbuf(&line_str),
1202 sizeof(s_utent.ut_line));
1203 str_free(&line_str);
1205 s_uwtmp_inserted = 1;
1206 s_utent.ut_type = USER_PROCESS;
1207 s_utent.ut_pid = vsf_sysutil_getpid();
1208 vsf_sysutil_strcpy(s_utent.ut_user, str_getbuf(p_user_str),
1209 sizeof(s_utent.ut_user));
1210 vsf_sysutil_strcpy(s_utent.ut_host, str_getbuf(p_host_str),
1211 sizeof(s_utent.ut_host));
1212 s_utent.ut_tv.tv_sec = vsf_sysutil_get_time_sec();
1213 setutxent();
1214 (void) pututxline(&s_utent);
1215 endutxent();
1216 updwtmpx(WTMPX_FILE, &s_utent);
1219 void
1220 vsf_remove_uwtmp(void)
1222 if (!s_uwtmp_inserted)
1224 return;
1226 s_uwtmp_inserted = 0;
1227 s_utent.ut_type = DEAD_PROCESS;
1228 vsf_sysutil_memclr(s_utent.ut_user, sizeof(s_utent.ut_user));
1229 vsf_sysutil_memclr(s_utent.ut_host, sizeof(s_utent.ut_host));
1230 s_utent.ut_tv.tv_sec = 0;
1231 setutxent();
1232 (void) pututxline(&s_utent);
1233 endutxent();
1234 s_utent.ut_tv.tv_sec = vsf_sysutil_get_time_sec();
1235 updwtmpx(WTMPX_FILE, &s_utent);
1238 #endif /* !VSF_SYSDEP_HAVE_UTMPX */
1240 void
1241 vsf_set_die_if_parent_dies()
1243 #ifdef VSF_SYSDEP_HAVE_SETPDEATHSIG
1244 if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0) != 0)
1246 die("prctl");
1248 #endif
1251 void
1252 vsf_set_term_if_parent_dies()
1254 #ifdef VSF_SYSDEP_HAVE_SETPDEATHSIG
1255 if (prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0) != 0)
1257 die("prctl");
1259 #endif
1263 vsf_sysutil_fork_isolate_all_failok()
1265 #ifdef VSF_SYSDEP_HAVE_LINUX_CLONE
1266 static int cloneflags_work = 1;
1267 if (cloneflags_work)
1269 int ret = syscall(__NR_clone,
1270 CLONE_NEWPID | CLONE_NEWIPC | CLONE_NEWNET | SIGCHLD,
1271 NULL);
1272 if (ret != -1 || (errno != EINVAL && errno != EPERM))
1274 if (ret == 0)
1276 vsf_sysutil_post_fork();
1278 return ret;
1280 cloneflags_work = 0;
1282 #endif
1283 return vsf_sysutil_fork_isolate_failok();
1287 vsf_sysutil_fork_isolate_failok()
1289 #ifdef VSF_SYSDEP_HAVE_LINUX_CLONE
1290 static int cloneflags_work = 1;
1291 if (cloneflags_work)
1293 int ret = syscall(__NR_clone, CLONE_NEWPID | CLONE_NEWIPC | SIGCHLD, NULL);
1294 if (ret != -1 || (errno != EINVAL && errno != EPERM))
1296 if (ret == 0)
1298 vsf_sysutil_post_fork();
1300 return ret;
1302 cloneflags_work = 0;
1304 #endif
1305 return vsf_sysutil_fork_failok();
1309 vsf_sysutil_fork_newnet()
1311 #ifdef VSF_SYSDEP_HAVE_LINUX_CLONE
1312 static int cloneflags_work = 1;
1313 if (cloneflags_work)
1315 int ret = syscall(__NR_clone, CLONE_NEWNET | SIGCHLD, NULL);
1316 if (ret != -1 || (errno != EINVAL && errno != EPERM))
1318 if (ret == 0)
1320 vsf_sysutil_post_fork();
1322 return ret;
1324 cloneflags_work = 0;
1326 #endif
1327 return vsf_sysutil_fork();
1331 vsf_sysutil_getpid_nocache(void)
1333 #ifdef VSF_SYSDEP_HAVE_LINUX_CLONE
1334 /* Need to defeat the glibc pid caching because we need to hit a raw
1335 * sys_clone() above.
1337 return syscall(__NR_getpid);
1338 #else
1339 return getpid();
1340 #endif