1/* 2 * This program is free software; you can redistribute it and/or 3 * modify it under the terms of the GNU General Public License as 4 * published by the Free Software Foundation; either version 2 of 5 * the License, or (at your option) any later version. 6 * 7 * This program is distributed in the hope that it will be useful, 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * GNU General Public License for more details. 11 * 12 * You should have received a copy of the GNU General Public License 13 * along with this program; if not, write to the Free Software 14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 15 * MA 02111-1307 USA 16 */ 17/* 18 * Part of Very Secure FTPd 19 * Licence: GPL v2 20 * Author: Chris Evans 21 * postprivparent.c 22 * 23 * This file contains all privileged parent services offered after logging 24 * in. This includes e.g. chown() of uploaded files, issuing of port 20 25 * sockets. 26 */ 27 28#include "postprivparent.h" 29#include "session.h" 30#include "privops.h" 31#include "privsock.h" 32#include "utility.h" 33#include "tunables.h" 34#include "defs.h" 35#include "sysutil.h" 36#include "str.h" 37#include "secutil.h" 38#include "sysstr.h" 39#include "sysdeputil.h" 40 41static void minimize_privilege(struct vsf_session* p_sess); 42static void process_post_login_req(struct vsf_session* p_sess); 43static void cmd_process_chown(struct vsf_session* p_sess); 44static void cmd_process_get_data_sock(struct vsf_session* p_sess); 45 46void 47vsf_priv_parent_postlogin(struct vsf_session* p_sess) 48{ 49 minimize_privilege(p_sess); 50 /* We're still here... */ 51 while (1) 52 { 53 process_post_login_req(p_sess); 54 } 55} 56 57static void 58process_post_login_req(struct vsf_session* p_sess) 59{ 60 char cmd; 61 vsf_sysutil_unblock_sig(kVSFSysUtilSigCHLD); 62 /* Blocks */ 63 cmd = priv_sock_get_cmd(p_sess->parent_fd); 64 vsf_sysutil_block_sig(kVSFSysUtilSigCHLD); 65 if (tunable_chown_uploads && cmd == PRIV_SOCK_CHOWN) 66 { 67 cmd_process_chown(p_sess); 68 } 69 else if (tunable_connect_from_port_20 && cmd == PRIV_SOCK_GET_DATA_SOCK) 70 { 71 cmd_process_get_data_sock(p_sess); 72 } 73 else 74 { 75 die("bad request in process_post_login_req"); 76 } 77} 78 79static void 80minimize_privilege(struct vsf_session* p_sess) 81{ 82 /* So, we logged in and forked a totally unprivileged child. Our job 83 * now is to minimize the privilege we need in order to act as a helper 84 * to the child. 85 * 86 * In some happy circumstances, we can exit and be done with root 87 * altogether. 88 */ 89 if (!p_sess->is_anonymous && tunable_session_support) 90 { 91 /* Need to hang around to update logs, utmp, wtmp etc. on logout. 92 * Need to keep privs to do this. */ 93 return; 94 } 95 if (!tunable_chown_uploads && !tunable_connect_from_port_20 && 96 !tunable_max_per_ip && !tunable_max_clients) 97 { 98 /* Cool. We're outta here. */ 99 vsf_sysutil_exit(0); 100 } 101 { 102 unsigned int caps = 0; 103 struct mystr user_str = INIT_MYSTR; 104 struct mystr dir_str = INIT_MYSTR; 105 str_alloc_text(&user_str, tunable_nopriv_user); 106 str_alloc_text(&dir_str, tunable_secure_chroot_dir); 107 if (tunable_chown_uploads) 108 { 109 caps |= kCapabilityCAP_CHOWN; 110 } 111 if (tunable_connect_from_port_20) 112 { 113 caps |= kCapabilityCAP_NET_BIND_SERVICE; 114 } 115 vsf_secutil_change_credentials(&user_str, &dir_str, 0, caps, 116 VSF_SECUTIL_OPTION_CHROOT); 117 str_free(&user_str); 118 str_free(&dir_str); 119 } 120} 121 122static void 123cmd_process_chown(struct vsf_session* p_sess) 124{ 125 int the_fd = priv_sock_recv_fd(p_sess->parent_fd); 126 vsf_privop_do_file_chown(p_sess, the_fd); 127 vsf_sysutil_close(the_fd); 128 priv_sock_send_result(p_sess->parent_fd, PRIV_SOCK_RESULT_OK); 129} 130 131static void 132cmd_process_get_data_sock(struct vsf_session* p_sess) 133{ 134 int sock_fd = vsf_privop_get_ftp_port_sock(p_sess); 135 priv_sock_send_result(p_sess->parent_fd, PRIV_SOCK_RESULT_OK); 136 priv_sock_send_fd(p_sess->parent_fd, sock_fd); 137 vsf_sysutil_close(sock_fd); 138} 139 140