usbmodeswitch: Updated to v.1.2.6 from shibby's branch.
[tomato.git] / release / src / router / vsftpd / sysdeputil.c
blobe0e9d765dba433e2aaa2360186719d0dcbd806f9
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_LINUX_SENDFILE
92 #ifdef PR_SET_KEEPCAPS
93 #define VSF_SYSDEP_HAVE_SETKEEPCAPS
94 #endif
95 #ifdef PR_SET_PDEATHSIG
96 #define VSF_SYSDEP_HAVE_SETPDEATHSIG
97 #endif
98 #endif
99 #endif
100 #endif
102 #if (defined(__FreeBSD__) && __FreeBSD__ >= 3)
103 #define VSF_SYSDEP_HAVE_FREEBSD_SENDFILE
104 #define VSF_SYSDEP_HAVE_SETPROCTITLE
105 #endif
107 #if defined(__NetBSD__)
108 #include <stdlib.h>
109 #define VSF_SYSDEP_HAVE_SETPROCTITLE
110 #include <sys/param.h>
111 #if __NetBSD_Version__ >= 106070000
112 #define WTMPX_FILE _PATH_WTMPX
113 #else
114 #undef VSF_SYSDEP_HAVE_UTMPX
115 #endif
116 #endif
118 #ifdef __hpux
119 #include <sys/socket.h>
120 #ifdef SF_DISCONNECT
121 #define VSF_SYSDEP_HAVE_HPUX_SENDFILE
122 #endif
123 #include <sys/param.h>
124 #include <sys/pstat.h>
125 #ifdef PSTAT_SETCMD
126 #define VSF_SYSDEP_HAVE_HPUX_SETPROCTITLE
127 #endif
128 #undef VSF_SYSDEP_HAVE_UTMPX
129 #endif
131 #include <unistd.h>
132 #include <sys/mman.h>
133 #ifdef MAP_ANON
134 #define VSF_SYSDEP_HAVE_MAP_ANON
135 #endif
137 #ifdef __sgi
138 #undef VSF_SYSDEP_HAVE_USERSHELL
139 #undef VSF_SYSDEP_HAVE_LIBCAP
140 #endif
142 #ifdef _AIX
143 #undef VSF_SYSDEP_HAVE_USERSHELL
144 #undef VSF_SYSDEP_HAVE_LIBCAP
145 #undef VSF_SYSDEP_HAVE_UTMPX
146 #undef VSF_SYSDEP_HAVE_PAM
147 #undef VSF_SYSDEP_HAVE_SHADOW
148 #undef VSF_SYSDEP_HAVE_SETPROCTITLE
149 #define VSF_SYSDEP_HAVE_AIX_SENDFILE
150 #define VSF_SYSDEP_TRY_LINUX_SETPROCTITLE_HACK
151 #define VSF_SYSDEP_HAVE_MAP_ANON
152 #endif
154 #ifdef __osf__
155 #undef VSF_SYSDEP_HAVE_USERSHELL
156 #endif
158 #if (defined(__sgi) || defined(__hpux) || defined(__osf__))
159 #define VSF_SYSDEP_NEED_OLD_FD_PASSING
160 #endif
162 #ifdef __sun
163 #define VSF_SYSDEP_HAVE_SOLARIS_SENDFILE
164 #endif
165 /* END config */
167 /* PAM support - we include our own dummy version if the system lacks this */
168 #include <security/pam_appl.h>
170 /* No PAM? Try getspnam() with a getpwnam() fallback */
171 #ifndef VSF_SYSDEP_HAVE_PAM
172 /* This may hit our own "dummy" include and undef VSF_SYSDEP_HAVE_SHADOW */
173 #include <shadow.h>
174 #include <pwd.h>
175 #include <unistd.h>
176 #include <crypt.h>
177 #endif
179 /* Prefer libcap based capabilities over raw syscall capabilities */
180 #include <sys/capability.h>
182 #if defined(VSF_SYSDEP_HAVE_CAPABILITIES) && !defined(VSF_SYSDEP_HAVE_LIBCAP)
183 #include <linux/unistd.h>
184 #include <linux/capability.h>
185 #include <errno.h>
186 #include <syscall.h>
187 int capset(cap_user_header_t header, const cap_user_data_t data)
189 return syscall(__NR_capset, header, data);
191 /* Gross HACK to avoid warnings - linux headers overlap glibc headers */
192 #undef __NFDBITS
193 #undef __FDMASK
194 #endif /* VSF_SYSDEP_HAVE_CAPABILITIES */
196 #if defined(VSF_SYSDEP_HAVE_LINUX_SENDFILE) || \
197 defined(VSF_SYSDEP_HAVE_SOLARIS_SENDFILE)
198 #include <sys/sendfile.h>
199 #elif defined(VSF_SYSDEP_HAVE_FREEBSD_SENDFILE)
200 #include <sys/types.h>
201 #include <sys/socket.h>
202 #elif defined(VSF_SYSDEP_HAVE_HPUX_SENDFILE)
203 #include <sys/socket.h>
204 #else /* VSF_SYSDEP_HAVE_LINUX_SENDFILE */
205 #include <unistd.h>
206 #endif /* VSF_SYSDEP_HAVE_LINUX_SENDFILE */
208 #ifdef VSF_SYSDEP_HAVE_SETPROCTITLE
209 #include <sys/types.h>
210 #include <unistd.h>
211 #endif
213 #ifdef VSF_SYSDEP_TRY_LINUX_SETPROCTITLE_HACK
214 extern char** environ;
215 static unsigned int s_proctitle_space = 0;
216 static int s_proctitle_inited = 0;
217 static char* s_p_proctitle = 0;
218 #endif
220 #ifndef VSF_SYSDEP_HAVE_MAP_ANON
221 #include <sys/types.h>
222 #include <sys/stat.h>
223 #include <fcntl.h>
224 static int s_zero_fd = -1;
225 #endif
227 /* File private functions/variables */
228 static int do_sendfile(const int out_fd, const int in_fd,
229 unsigned int num_send, filesize_t start_pos);
230 static void vsf_sysutil_setproctitle_internal(const char* p_text);
231 static struct mystr s_proctitle_prefix_str;
233 /* These two aren't static to avoid OpenBSD build warnings. */
234 void vsf_insert_uwtmp(const struct mystr* p_user_str,
235 const struct mystr* p_host_str);
236 void vsf_remove_uwtmp(void);
238 #ifndef VSF_SYSDEP_HAVE_PAM
240 vsf_sysdep_check_auth(struct mystr* p_user_str,
241 const struct mystr* p_pass_str,
242 const struct mystr* p_remote_host)
244 const char* p_crypted;
245 const struct passwd* p_pwd = (struct passwd*) vsf_sysutil_getpwnam(str_getbuf(p_user_str));
246 (void) p_remote_host;
247 if (p_pwd == NULL)
249 return 0;
251 #ifdef VSF_SYSDEP_HAVE_USERSHELL
252 if (tunable_check_shell)
254 const char* p_shell;
255 while ((p_shell = getusershell()) != NULL)
257 if (!vsf_sysutil_strcmp(p_shell, p_pwd->pw_shell))
259 break;
262 endusershell();
263 if (p_shell == NULL)
265 return 0;
268 #endif
269 #ifdef VSF_SYSDEP_HAVE_SHADOW
271 const struct spwd* p_spwd = getspnam(str_getbuf(p_user_str));
272 if (p_spwd != NULL)
274 long curr_time = vsf_sysutil_get_time_sec();
275 int days;
276 days = curr_time / (60 * 60 * 24);
277 if (p_spwd->sp_expire > 0 && p_spwd->sp_expire < days)
279 return 0;
281 if (p_spwd->sp_lstchg > 0 && p_spwd->sp_max > 0 &&
282 p_spwd->sp_lstchg + p_spwd->sp_max < days)
284 return 0;
286 p_crypted = crypt(str_getbuf(p_pass_str), p_spwd->sp_pwdp);
287 if (!vsf_sysutil_strcmp(p_crypted, p_spwd->sp_pwdp))
289 return 1;
293 #endif /* VSF_SYSDEP_HAVE_SHADOW */
294 p_crypted = crypt(str_getbuf(p_pass_str), p_pwd->pw_passwd);
295 if (!vsf_sysutil_strcmp(p_crypted, p_pwd->pw_passwd))
297 return 1;
299 return 0;
302 #else /* VSF_SYSDEP_HAVE_PAM */
304 #if (defined(__sun) || defined(__hpux)) && \
305 !defined(LINUX_PAM) && !defined(_OPENPAM)
306 /* Sun's PAM doesn't use const here, while Linux-PAM and OpenPAM do */
307 #define lo_const
308 #else
309 #define lo_const const
310 #endif
311 typedef lo_const void* pam_item_t;
313 static pam_handle_t* s_pamh;
314 static struct mystr s_pword_str;
315 static int pam_conv_func(int nmsg, const struct pam_message** p_msg,
316 struct pam_response** p_reply, void* p_addata);
317 static void vsf_auth_shutdown(void);
320 vsf_sysdep_check_auth(struct mystr* p_user_str,
321 const struct mystr* p_pass_str,
322 const struct mystr* p_remote_host)
324 int retval;
325 pam_item_t item;
326 const char* pam_user_name = 0;
327 struct pam_conv the_conv =
329 &pam_conv_func,
332 if (s_pamh != 0)
334 bug("vsf_sysdep_check_auth");
336 str_copy(&s_pword_str, p_pass_str);
337 retval = pam_start(tunable_pam_service_name,
338 str_getbuf(p_user_str), &the_conv, &s_pamh);
339 if (retval != PAM_SUCCESS)
341 s_pamh = 0;
342 return 0;
344 #ifdef PAM_RHOST
345 retval = pam_set_item(s_pamh, PAM_RHOST, str_getbuf(p_remote_host));
346 if (retval != PAM_SUCCESS)
348 (void) pam_end(s_pamh, retval);
349 s_pamh = 0;
350 return 0;
352 #endif
353 #ifdef PAM_TTY
354 retval = pam_set_item(s_pamh, PAM_TTY, "ftp");
355 if (retval != PAM_SUCCESS)
357 (void) pam_end(s_pamh, retval);
358 s_pamh = 0;
359 return 0;
361 #endif
362 #ifdef PAM_RUSER
363 retval = pam_set_item(s_pamh, PAM_RUSER, str_getbuf(p_user_str));
364 if (retval != PAM_SUCCESS)
366 (void) pam_end(s_pamh, retval);
367 s_pamh = 0;
368 return 0;
370 #endif
371 retval = pam_authenticate(s_pamh, 0);
372 if (retval != PAM_SUCCESS)
374 (void) pam_end(s_pamh, retval);
375 s_pamh = 0;
376 return 0;
378 #ifdef PAM_USER
379 retval = pam_get_item(s_pamh, PAM_USER, &item);
380 if (retval != PAM_SUCCESS)
382 (void) pam_end(s_pamh, retval);
383 s_pamh = 0;
384 return 0;
386 pam_user_name = item;
387 str_alloc_text(p_user_str, pam_user_name);
388 #endif
389 retval = pam_acct_mgmt(s_pamh, 0);
390 if (retval != PAM_SUCCESS)
392 (void) pam_end(s_pamh, retval);
393 s_pamh = 0;
394 return 0;
396 retval = pam_setcred(s_pamh, PAM_ESTABLISH_CRED);
397 if (retval != PAM_SUCCESS)
399 (void) pam_end(s_pamh, retval);
400 s_pamh = 0;
401 return 0;
403 if (!tunable_session_support)
405 /* You're in already! */
406 (void) pam_end(s_pamh, retval);
407 s_pamh = 0;
408 return 1;
410 /* Must do this BEFORE opening a session for pam_limits to count us */
411 vsf_insert_uwtmp(p_user_str, p_remote_host);
412 retval = pam_open_session(s_pamh, 0);
413 if (retval != PAM_SUCCESS)
415 vsf_remove_uwtmp();
416 (void) pam_setcred(s_pamh, PAM_DELETE_CRED);
417 (void) pam_end(s_pamh, retval);
418 s_pamh = 0;
419 return 0;
421 /* We MUST ensure the PAM session, utmp, wtmp etc. are cleaned up, however
422 * we exit.
424 vsf_sysutil_set_exit_func(vsf_auth_shutdown);
425 /* You're in dude */
426 return 1;
429 static void
430 vsf_auth_shutdown(void)
432 if (s_pamh == 0)
434 bug("vsf_auth_shutdown");
436 (void) pam_close_session(s_pamh, 0);
437 (void) pam_setcred(s_pamh, PAM_DELETE_CRED);
438 (void) pam_end(s_pamh, PAM_SUCCESS);
439 s_pamh = 0;
440 vsf_remove_uwtmp();
443 static int
444 pam_conv_func(int nmsg, const struct pam_message** p_msg,
445 struct pam_response** p_reply, void* p_addata)
447 int i;
448 struct pam_response* p_resps = 0;
449 (void) p_addata;
450 if (nmsg < 0)
452 bug("dodgy nmsg in pam_conv_func");
454 p_resps = vsf_sysutil_malloc(sizeof(struct pam_response) * nmsg);
455 for (i=0; i<nmsg; i++)
457 switch (p_msg[i]->msg_style)
459 case PAM_PROMPT_ECHO_OFF:
460 p_resps[i].resp_retcode = PAM_SUCCESS;
461 p_resps[i].resp = (char*) str_strdup(&s_pword_str);
462 break;
463 case PAM_TEXT_INFO:
464 case PAM_ERROR_MSG:
465 p_resps[i].resp_retcode = PAM_SUCCESS;
466 p_resps[i].resp = 0;
467 break;
468 case PAM_PROMPT_ECHO_ON:
469 default:
470 vsf_sysutil_free(p_resps);
471 return PAM_CONV_ERR;
472 break;
475 *p_reply = p_resps;
476 return PAM_SUCCESS;
479 #endif /* VSF_SYSDEP_HAVE_PAM */
481 /* Capabilities support (or lack thereof) */
482 void
483 vsf_sysdep_keep_capabilities(void)
485 if (!vsf_sysdep_has_capabilities_as_non_root())
487 bug("asked to keep capabilities, but no support exists");
489 #ifdef VSF_SYSDEP_HAVE_SETKEEPCAPS
491 int retval = prctl(PR_SET_KEEPCAPS, 1);
492 if (vsf_sysutil_retval_is_error(retval))
494 die("prctl");
497 #endif /* VSF_SYSDEP_HAVE_SETKEEPCAPS */
499 #if !defined(VSF_SYSDEP_HAVE_CAPABILITIES) && !defined(VSF_SYSDEP_HAVE_LIBCAP)
502 vsf_sysdep_has_capabilities(void)
504 return 0;
508 vsf_sysdep_has_capabilities_as_non_root(void)
510 return 0;
513 void
514 vsf_sysdep_adopt_capabilities(unsigned int caps)
516 (void) caps;
517 bug("asked to adopt capabilities, but no support exists");
520 #else /* VSF_SYSDEP_HAVE_CAPABILITIES || VSF_SYSDEP_HAVE_LIBCAP */
522 static int do_checkcap(void);
525 vsf_sysdep_has_capabilities_as_non_root(void)
527 static int s_prctl_checked;
528 static int s_runtime_prctl_works;
529 if (!s_prctl_checked)
531 #ifdef VSF_SYSDEP_HAVE_SETKEEPCAPS
532 /* Clarity: note embedded call to prctl() syscall */
533 if (!vsf_sysutil_retval_is_error(prctl(PR_SET_KEEPCAPS, 0)))
535 s_runtime_prctl_works = 1;
537 #endif /* VSF_SYSDEP_HAVE_SETKEEPCAPS */
538 s_prctl_checked = 1;
540 return s_runtime_prctl_works;
544 vsf_sysdep_has_capabilities(void)
546 /* Even though compiled with capabilities, the runtime system may lack them.
547 * Also, RH7.0 kernel headers advertise a 2.4.0 box, but on a 2.2.x kernel!
549 static int s_caps_checked;
550 static int s_runtime_has_caps;
551 if (!s_caps_checked)
553 s_runtime_has_caps = do_checkcap();
554 s_caps_checked = 1;
556 return s_runtime_has_caps;
559 #ifndef VSF_SYSDEP_HAVE_LIBCAP
560 static int
561 do_checkcap(void)
563 /* EFAULT (EINVAL if page 0 mapped) vs. ENOSYS */
564 int retval = capset(0, 0);
565 if (!vsf_sysutil_retval_is_error(retval) ||
566 vsf_sysutil_get_error() != kVSFSysUtilErrNOSYS)
568 return 1;
570 return 0;
573 void
574 vsf_sysdep_adopt_capabilities(unsigned int caps)
576 /* n.b. yes I know I should be using libcap!! */
577 int retval;
578 struct __user_cap_header_struct cap_head;
579 struct __user_cap_data_struct cap_data;
580 __u32 cap_mask = 0;
581 if (!caps)
583 bug("asked to adopt no capabilities");
585 vsf_sysutil_memclr(&cap_head, sizeof(cap_head));
586 vsf_sysutil_memclr(&cap_data, sizeof(cap_data));
587 cap_head.version = _LINUX_CAPABILITY_VERSION;
588 cap_head.pid = 0;
589 if (caps & kCapabilityCAP_CHOWN)
591 cap_mask |= (1 << CAP_CHOWN);
593 if (caps & kCapabilityCAP_NET_BIND_SERVICE)
595 cap_mask |= (1 << CAP_NET_BIND_SERVICE);
597 cap_data.effective = cap_data.permitted = cap_mask;
598 cap_data.inheritable = 0;
599 retval = capset(&cap_head, &cap_data);
600 if (retval != 0)
602 die("capset");
606 #else /* VSF_SYSDEP_HAVE_LIBCAP */
607 static int
608 do_checkcap(void)
610 cap_t current_caps = cap_get_proc();
611 cap_free(current_caps);
612 if (current_caps != NULL)
614 return 1;
616 return 0;
619 void
620 vsf_sysdep_adopt_capabilities(unsigned int caps)
622 int retval;
623 cap_value_t cap_value;
624 cap_t adopt_caps = cap_init();
625 if (caps & kCapabilityCAP_CHOWN)
627 cap_value = CAP_CHOWN;
628 cap_set_flag(adopt_caps, CAP_EFFECTIVE, 1, &cap_value, CAP_SET);
629 cap_set_flag(adopt_caps, CAP_PERMITTED, 1, &cap_value, CAP_SET);
631 if (caps & kCapabilityCAP_NET_BIND_SERVICE)
633 cap_value = CAP_NET_BIND_SERVICE;
634 cap_set_flag(adopt_caps, CAP_EFFECTIVE, 1, &cap_value, CAP_SET);
635 cap_set_flag(adopt_caps, CAP_PERMITTED, 1, &cap_value, CAP_SET);
637 retval = cap_set_proc(adopt_caps);
638 if (retval != 0)
640 die("cap_set_proc");
642 cap_free(adopt_caps);
645 #endif /* !VSF_SYSDEP_HAVE_LIBCAP */
646 #endif /* VSF_SYSDEP_HAVE_CAPABILITIES || VSF_SYSDEP_HAVE_LIBCAP */
649 vsf_sysutil_sendfile(const int out_fd, const int in_fd,
650 filesize_t* p_offset, filesize_t num_send,
651 unsigned int max_chunk)
653 /* Grr - why is off_t signed? */
654 if (*p_offset < 0 || num_send < 0)
656 die("invalid offset or send count in vsf_sysutil_sendfile");
658 if (max_chunk == 0)
660 max_chunk = INT_MAX;
662 while (num_send > 0)
664 int retval;
665 unsigned int send_this_time;
666 if (num_send > max_chunk)
668 send_this_time = max_chunk;
670 else
672 send_this_time = (unsigned int) num_send;
674 /* Keep input file position in line with sendfile() calls */
675 vsf_sysutil_lseek_to(in_fd, *p_offset);
676 retval = do_sendfile(out_fd, in_fd, send_this_time, *p_offset);
677 if (vsf_sysutil_retval_is_error(retval) || retval == 0)
679 return retval;
681 num_send -= retval;
682 *p_offset += retval;
684 return 0;
687 static int do_sendfile(const int out_fd, const int in_fd,
688 unsigned int num_send, filesize_t start_pos)
690 /* Probably should one day be shared with instance in ftpdataio.c */
691 static char* p_recvbuf;
692 unsigned int total_written = 0;
693 int retval;
694 enum EVSFSysUtilError error;
695 (void) start_pos;
696 (void) error;
697 #if defined(VSF_SYSDEP_HAVE_LINUX_SENDFILE) || \
698 defined(VSF_SYSDEP_HAVE_FREEBSD_SENDFILE) || \
699 defined(VSF_SYSDEP_HAVE_HPUX_SENDFILE) || \
700 defined(VSF_SYSDEP_HAVE_AIX_SENDFILE) || \
701 defined(VSF_SYSDEP_HAVE_SOLARIS_SENDFILE)
702 if (tunable_use_sendfile)
704 static int s_sendfile_checked;
705 static int s_runtime_sendfile_works;
706 if (!s_sendfile_checked || s_runtime_sendfile_works)
710 #ifdef VSF_SYSDEP_HAVE_LINUX_SENDFILE
711 retval = sendfile(out_fd, in_fd, NULL, num_send);
712 #elif defined(VSF_SYSDEP_HAVE_FREEBSD_SENDFILE)
714 /* XXX - start_pos will truncate on 32-bit machines - can we
715 * say "start from current pos"?
717 off_t written = 0;
718 retval = sendfile(in_fd, out_fd, start_pos, num_send, NULL,
719 &written, 0);
720 /* Translate to Linux-like retval */
721 if (written > 0)
723 retval = (int) written;
726 #elif defined(VSF_SYSDEP_HAVE_SOLARIS_SENDFILE)
728 size_t written = 0;
729 struct sendfilevec the_vec;
730 vsf_sysutil_memclr(&the_vec, sizeof(the_vec));
731 the_vec.sfv_fd = in_fd;
732 the_vec.sfv_off = start_pos;
733 the_vec.sfv_len = num_send;
734 retval = sendfilev(out_fd, &the_vec, 1, &written);
735 /* Translate to Linux-like retval */
736 if (written > 0)
738 retval = (int) written;
741 #elif defined(VSF_SYSDEP_HAVE_AIX_SENDFILE)
743 struct sf_parms sf_iobuf;
744 vsf_sysutil_memclr(&sf_iobuf, sizeof(sf_iobuf));
745 sf_iobuf.header_data = NULL;
746 sf_iobuf.header_length = 0;
747 sf_iobuf.trailer_data = NULL;
748 sf_iobuf.trailer_length = 0;
749 sf_iobuf.file_descriptor = in_fd;
750 sf_iobuf.file_offset = start_pos;
751 sf_iobuf.file_bytes = num_send;
753 retval = send_file((int*)&out_fd, &sf_iobuf, 0);
754 if (retval >= 0)
756 retval = sf_iobuf.bytes_sent;
759 #else /* must be VSF_SYSDEP_HAVE_HPUX_SENDFILE */
761 retval = sendfile(out_fd, in_fd, start_pos, num_send, NULL, 0);
763 #endif /* VSF_SYSDEP_HAVE_LINUX_SENDFILE */
764 error = vsf_sysutil_get_error();
765 vsf_sysutil_check_pending_actions(kVSFSysUtilIO, retval, out_fd);
767 while (vsf_sysutil_retval_is_error(retval) &&
768 error == kVSFSysUtilErrINTR);
769 if (!s_sendfile_checked)
771 s_sendfile_checked = 1;
772 if (!vsf_sysutil_retval_is_error(retval) ||
773 error != kVSFSysUtilErrNOSYS)
775 s_runtime_sendfile_works = 1;
778 if (!vsf_sysutil_retval_is_error(retval))
780 return retval;
782 if (s_runtime_sendfile_works && error != kVSFSysUtilErrINVAL &&
783 error != kVSFSysUtilErrOPNOTSUPP)
785 return retval;
787 /* Fall thru to normal implementation. We won't check again. NOTE -
788 * also falls through if sendfile() is OK but it returns EINVAL. For
789 * Linux this means the file was not page cache backed. Original
790 * complaint was trying to serve files from an NTFS filesystem!
794 #endif /* VSF_SYSDEP_HAVE_LINUX_SENDFILE || VSF_SYSDEP_HAVE_FREEBSD_SENDFILE */
795 if (p_recvbuf == 0)
797 vsf_secbuf_alloc(&p_recvbuf, VSFTP_DATA_BUFSIZE);
799 while (1)
801 unsigned int num_read;
802 unsigned int num_written;
803 unsigned int num_read_this_time = VSFTP_DATA_BUFSIZE;
804 if (num_read_this_time > num_send)
806 num_read_this_time = num_send;
808 retval = vsf_sysutil_read(in_fd, p_recvbuf, num_read_this_time);
809 if (retval < 0)
811 return retval;
813 else if (retval == 0)
815 return -1;
817 num_read = (unsigned int) retval;
818 retval = vsf_sysutil_write_loop(out_fd, p_recvbuf, num_read);
819 if (retval < 0)
821 return retval;
823 num_written = (unsigned int) retval;
824 total_written += num_written;
825 if (num_written != num_read)
827 return num_written;
829 if (num_written > num_send)
831 bug("num_written bigger than num_send in do_sendfile");
833 num_send -= num_written;
834 if (num_send == 0)
836 /* Bingo! */
837 return total_written;
842 void
843 vsf_sysutil_set_proctitle_prefix(const struct mystr* p_str)
845 str_copy(&s_proctitle_prefix_str, p_str);
848 /* This delegation is common to all setproctitle() implementations */
849 void
850 vsf_sysutil_setproctitle_str(const struct mystr* p_str)
852 vsf_sysutil_setproctitle(str_getbuf(p_str));
855 void
856 vsf_sysutil_setproctitle(const char* p_text)
858 struct mystr proctitle_str = INIT_MYSTR;
859 str_copy(&proctitle_str, &s_proctitle_prefix_str);
860 if (!str_isempty(&proctitle_str))
862 str_append_text(&proctitle_str, ": ");
864 str_append_text(&proctitle_str, p_text);
865 vsf_sysutil_setproctitle_internal(str_getbuf(&proctitle_str));
866 str_free(&proctitle_str);
869 #ifdef VSF_SYSDEP_HAVE_SETPROCTITLE
870 void
871 vsf_sysutil_setproctitle_init(int argc, const char* argv[])
873 (void) argc;
874 (void) argv;
877 void
878 vsf_sysutil_setproctitle_internal(const char* p_buf)
880 setproctitle("%s", p_buf);
882 #elif defined(VSF_SYSDEP_HAVE_HPUX_SETPROCTITLE)
883 void
884 vsf_sysutil_setproctitle_init(int argc, const char* argv[])
886 (void) argc;
887 (void) argv;
890 void
891 vsf_sysutil_setproctitle_internal(const char* p_buf)
893 struct mystr proctitle_str = INIT_MYSTR;
894 union pstun p;
895 str_alloc_text(&proctitle_str, "vsftpd: ");
896 str_append_text(&proctitle_str, p_buf);
897 p.pst_command = str_getbuf(&proctitle_str);
898 pstat(PSTAT_SETCMD, p, 0, 0, 0);
899 str_free(&proctitle_str);
901 #elif defined(VSF_SYSDEP_TRY_LINUX_SETPROCTITLE_HACK)
902 void
903 vsf_sysutil_setproctitle_init(int argc, const char* argv[])
905 int i;
906 char** p_env = environ;
907 if (s_proctitle_inited)
909 bug("vsf_sysutil_setproctitle_init called twice");
911 s_proctitle_inited = 1;
912 if (argv[0] == 0)
914 die("no argv[0] in vsf_sysutil_setproctitle_init");
916 for (i=0; i<argc; i++)
918 s_proctitle_space += vsf_sysutil_strlen(argv[i]) + 1;
919 if (i > 0)
921 argv[i] = 0;
924 while (*p_env != 0)
926 s_proctitle_space += vsf_sysutil_strlen(*p_env) + 1;
927 p_env++;
929 /* Oops :-) */
930 environ = 0;
931 s_p_proctitle = (char*) argv[0];
932 vsf_sysutil_memclr(s_p_proctitle, s_proctitle_space);
935 void
936 vsf_sysutil_setproctitle_internal(const char* p_buf)
938 struct mystr proctitle_str = INIT_MYSTR;
939 unsigned int to_copy;
940 if (!s_proctitle_inited)
942 bug("vsf_sysutil_setproctitle: not initialized");
944 vsf_sysutil_memclr(s_p_proctitle, s_proctitle_space);
945 if (s_proctitle_space < 32)
947 return;
949 str_alloc_text(&proctitle_str, "vsftpd: ");
950 str_append_text(&proctitle_str, p_buf);
951 to_copy = str_getlen(&proctitle_str);
952 if (to_copy > s_proctitle_space - 1)
954 to_copy = s_proctitle_space - 1;
956 vsf_sysutil_memcpy(s_p_proctitle, str_getbuf(&proctitle_str), to_copy);
957 str_free(&proctitle_str);
958 s_p_proctitle[to_copy] = '\0';
960 #else /* VSF_SYSDEP_HAVE_SETPROCTITLE */
961 void
962 vsf_sysutil_setproctitle_init(int argc, const char* argv[])
964 (void) argc;
965 (void) argv;
968 void
969 vsf_sysutil_setproctitle_internal(const char* p_buf)
971 (void) p_buf;
973 #endif /* VSF_SYSDEP_HAVE_SETPROCTITLE */
975 #ifdef VSF_SYSDEP_HAVE_MAP_ANON
976 void
977 vsf_sysutil_map_anon_pages_init(void)
981 void*
982 vsf_sysutil_map_anon_pages(unsigned int length)
984 char* retval = mmap(0, length, PROT_READ | PROT_WRITE,
985 MAP_PRIVATE | MAP_ANON, -1, 0);
986 if (retval == MAP_FAILED)
988 die("mmap");
990 return retval;
992 #else /* VSF_SYSDEP_HAVE_MAP_ANON */
993 void
994 vsf_sysutil_map_anon_pages_init(void)
996 if (s_zero_fd != -1)
998 bug("vsf_sysutil_map_anon_pages_init called twice");
1000 s_zero_fd = open("/dev/zero", O_RDWR);
1001 if (s_zero_fd < 0)
1003 die("could not open /dev/zero");
1007 void*
1008 vsf_sysutil_map_anon_pages(unsigned int length)
1010 char* retval = mmap(0, length, PROT_READ | PROT_WRITE,
1011 MAP_PRIVATE, s_zero_fd, 0);
1012 if (retval == MAP_FAILED)
1014 die("mmap");
1016 return retval;
1018 #endif /* VSF_SYSDEP_HAVE_MAP_ANON */
1020 #ifndef VSF_SYSDEP_NEED_OLD_FD_PASSING
1022 void
1023 vsf_sysutil_send_fd(int sock_fd, int send_fd)
1025 int retval;
1026 struct msghdr msg;
1027 struct cmsghdr* p_cmsg;
1028 struct iovec vec;
1029 char cmsgbuf[CMSG_SPACE(sizeof(send_fd))];
1030 int* p_fds;
1031 char sendchar = 0;
1032 msg.msg_control = cmsgbuf;
1033 msg.msg_controllen = sizeof(cmsgbuf);
1034 p_cmsg = CMSG_FIRSTHDR(&msg);
1035 p_cmsg->cmsg_level = SOL_SOCKET;
1036 p_cmsg->cmsg_type = SCM_RIGHTS;
1037 p_cmsg->cmsg_len = CMSG_LEN(sizeof(send_fd));
1038 p_fds = (int*)CMSG_DATA(p_cmsg);
1039 *p_fds = send_fd;
1040 msg.msg_controllen = p_cmsg->cmsg_len;
1041 msg.msg_name = NULL;
1042 msg.msg_namelen = 0;
1043 msg.msg_iov = &vec;
1044 msg.msg_iovlen = 1;
1045 msg.msg_flags = 0;
1046 /* "To pass file descriptors or credentials you need to send/read at
1047 * least on byte" (man 7 unix)
1049 vec.iov_base = &sendchar;
1050 vec.iov_len = sizeof(sendchar);
1051 retval = sendmsg(sock_fd, &msg, 0);
1052 if (retval != 1)
1054 die("sendmsg");
1059 vsf_sysutil_recv_fd(const int sock_fd)
1061 int retval;
1062 struct msghdr msg;
1063 char recvchar;
1064 struct iovec vec;
1065 int recv_fd;
1066 char cmsgbuf[CMSG_SPACE(sizeof(recv_fd))];
1067 struct cmsghdr* p_cmsg;
1068 int* p_fd;
1069 vec.iov_base = &recvchar;
1070 vec.iov_len = sizeof(recvchar);
1071 msg.msg_name = NULL;
1072 msg.msg_namelen = 0;
1073 msg.msg_iov = &vec;
1074 msg.msg_iovlen = 1;
1075 msg.msg_control = cmsgbuf;
1076 msg.msg_controllen = sizeof(cmsgbuf);
1077 msg.msg_flags = 0;
1078 /* In case something goes wrong, set the fd to -1 before the syscall */
1079 p_fd = (int*)CMSG_DATA(CMSG_FIRSTHDR(&msg));
1080 *p_fd = -1;
1081 retval = recvmsg(sock_fd, &msg, 0);
1082 if (retval != 1)
1084 die("recvmsg");
1086 p_cmsg = CMSG_FIRSTHDR(&msg);
1087 if (p_cmsg == NULL)
1089 die("no passed fd");
1091 /* We used to verify the returned cmsg_level, cmsg_type and cmsg_len here,
1092 * but Linux 2.0 totally uselessly fails to fill these in.
1094 p_fd = (int*)CMSG_DATA(p_cmsg);
1095 recv_fd = *p_fd;
1096 if (recv_fd == -1)
1098 die("no passed fd");
1100 return recv_fd;
1103 #else /* !VSF_SYSDEP_NEED_OLD_FD_PASSING */
1105 void
1106 vsf_sysutil_send_fd(int sock_fd, int send_fd)
1108 int retval;
1109 char send_char = 0;
1110 struct msghdr msg;
1111 struct iovec vec;
1112 vec.iov_base = &send_char;
1113 vec.iov_len = 1;
1114 msg.msg_name = NULL;
1115 msg.msg_namelen = 0;
1116 msg.msg_iov = &vec;
1117 msg.msg_iovlen = 1;
1118 msg.msg_accrights = (caddr_t) &send_fd;
1119 msg.msg_accrightslen = sizeof(send_fd);
1120 retval = sendmsg(sock_fd, &msg, 0);
1121 if (retval != 1)
1123 die("sendmsg");
1128 vsf_sysutil_recv_fd(int sock_fd)
1130 int retval;
1131 struct msghdr msg;
1132 struct iovec vec;
1133 char recv_char;
1134 int recv_fd = -1;
1135 vec.iov_base = &recv_char;
1136 vec.iov_len = 1;
1137 msg.msg_name = NULL;
1138 msg.msg_namelen = 0;
1139 msg.msg_iov = &vec;
1140 msg.msg_iovlen = 1;
1141 msg.msg_accrights = (caddr_t) &recv_fd;
1142 msg.msg_accrightslen = sizeof(recv_fd);
1143 retval = recvmsg(sock_fd, &msg, 0);
1144 if (retval != 1)
1146 die("recvmsg");
1148 if (recv_fd == -1)
1150 die("no passed fd");
1152 return recv_fd;
1155 #endif /* !VSF_SYSDEP_NEED_OLD_FD_PASSING */
1157 #ifndef VSF_SYSDEP_HAVE_UTMPX
1159 void
1160 vsf_insert_uwtmp(const struct mystr* p_user_str,
1161 const struct mystr* p_host_str)
1163 (void) p_user_str;
1164 (void) p_host_str;
1167 void
1168 vsf_remove_uwtmp(void)
1172 #else /* !VSF_SYSDEP_HAVE_UTMPX */
1174 /* IMHO, the pam_unix module REALLY should be doing this in its SM component */
1175 /* Statics */
1176 static int s_uwtmp_inserted;
1177 static struct utmpx s_utent;
1179 void
1180 vsf_insert_uwtmp(const struct mystr* p_user_str,
1181 const struct mystr* p_host_str)
1183 if (sizeof(s_utent.ut_line) < 16)
1185 return;
1187 if (s_uwtmp_inserted)
1189 bug("vsf_insert_uwtmp");
1192 struct mystr line_str = INIT_MYSTR;
1193 str_alloc_text(&line_str, "vsftpd:");
1194 str_append_ulong(&line_str, vsf_sysutil_getpid());
1195 if (str_getlen(&line_str) >= sizeof(s_utent.ut_line))
1197 str_free(&line_str);
1198 return;
1200 vsf_sysutil_strcpy(s_utent.ut_line, str_getbuf(&line_str),
1201 sizeof(s_utent.ut_line));
1202 str_free(&line_str);
1204 s_uwtmp_inserted = 1;
1205 s_utent.ut_type = USER_PROCESS;
1206 s_utent.ut_pid = vsf_sysutil_getpid();
1207 vsf_sysutil_strcpy(s_utent.ut_user, str_getbuf(p_user_str),
1208 sizeof(s_utent.ut_user));
1209 vsf_sysutil_strcpy(s_utent.ut_host, str_getbuf(p_host_str),
1210 sizeof(s_utent.ut_host));
1211 s_utent.ut_tv.tv_sec = vsf_sysutil_get_time_sec();
1212 setutxent();
1213 (void) pututxline(&s_utent);
1214 endutxent();
1215 updwtmpx(WTMPX_FILE, &s_utent);
1218 void
1219 vsf_remove_uwtmp(void)
1221 if (!s_uwtmp_inserted)
1223 return;
1225 s_uwtmp_inserted = 0;
1226 s_utent.ut_type = DEAD_PROCESS;
1227 vsf_sysutil_memclr(s_utent.ut_user, sizeof(s_utent.ut_user));
1228 vsf_sysutil_memclr(s_utent.ut_host, sizeof(s_utent.ut_host));
1229 s_utent.ut_tv.tv_sec = 0;
1230 setutxent();
1231 (void) pututxline(&s_utent);
1232 endutxent();
1233 s_utent.ut_tv.tv_sec = vsf_sysutil_get_time_sec();
1234 updwtmpx(WTMPX_FILE, &s_utent);
1237 #endif /* !VSF_SYSDEP_HAVE_UTMPX */
1239 void
1240 vsf_set_die_if_parent_dies()
1242 #ifdef VSF_SYSDEP_HAVE_SETPDEATHSIG
1243 if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0) != 0)
1245 die("prctl");
1247 #endif
1250 void
1251 vsf_set_term_if_parent_dies()
1253 #ifdef VSF_SYSDEP_HAVE_SETPDEATHSIG
1254 if (prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0) != 0)
1256 die("prctl");
1258 #endif
1262 vsf_sysutil_fork_isolate_all_failok()
1264 #ifdef VSF_SYSDEP_HAVE_LINUX_CLONE
1265 static int cloneflags_work = 1;
1266 if (cloneflags_work)
1268 int ret = syscall(__NR_clone,
1269 CLONE_NEWPID | CLONE_NEWIPC | CLONE_NEWNET | SIGCHLD,
1270 NULL);
1271 if (ret != -1 || (errno != EINVAL && errno != EPERM))
1273 if (ret == 0)
1275 vsf_sysutil_post_fork();
1277 return ret;
1279 cloneflags_work = 0;
1281 #endif
1282 return vsf_sysutil_fork_isolate_failok();
1286 vsf_sysutil_fork_isolate_failok()
1288 #ifdef VSF_SYSDEP_HAVE_LINUX_CLONE
1289 static int cloneflags_work = 1;
1290 if (cloneflags_work)
1292 int ret = syscall(__NR_clone, CLONE_NEWPID | CLONE_NEWIPC | SIGCHLD, NULL);
1293 if (ret != -1 || (errno != EINVAL && errno != EPERM))
1295 if (ret == 0)
1297 vsf_sysutil_post_fork();
1299 return ret;
1301 cloneflags_work = 0;
1303 #endif
1304 return vsf_sysutil_fork_failok();
1308 vsf_sysutil_fork_newnet()
1310 #ifdef VSF_SYSDEP_HAVE_LINUX_CLONE
1311 static int cloneflags_work = 1;
1312 if (cloneflags_work)
1314 int ret = syscall(__NR_clone, CLONE_NEWNET | SIGCHLD, NULL);
1315 if (ret != -1 || (errno != EINVAL && errno != EPERM))
1317 if (ret == 0)
1319 vsf_sysutil_post_fork();
1321 return ret;
1323 cloneflags_work = 0;
1325 #endif
1326 return vsf_sysutil_fork();
1330 vsf_sysutil_getpid_nocache(void)
1332 #ifdef VSF_SYSDEP_HAVE_LINUX_CLONE
1333 /* Need to defeat the glibc pid caching because we need to hit a raw
1334 * sys_clone() above.
1336 return syscall(__NR_getpid);
1337 #else
1338 return getpid();
1339 #endif