# HG changeset patch # User tomas klacko - Sun Microsystems - Prague Czech Republic # Date 1330366470 28800 # Node ID 5953149bd7437e6788b431c6500e60e77bf64a04 # Parent 6e61f0012046b7e1975f528f0c0a3ebae57cad55 7130322 proftpd in the default configuration does not have required privileges diff -r 6e61f0012046 -r 5953149bd743 components/proftpd/mod_solaris_priv.c --- a/components/proftpd/mod_solaris_priv.c Fri Feb 24 13:30:24 2012 -0800 +++ b/components/proftpd/mod_solaris_priv.c Mon Feb 27 10:14:30 2012 -0800 @@ -2,7 +2,7 @@ * ProFTPD - FTP server daemon * Copyright (c) 1997, 1998 Public Flood Software * Copyright (c) 2003-2010 The ProFTPD Project team - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -169,6 +169,12 @@ /* Needed to access /dev/urandom. */ priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_SYS_DEVICES, NULL); + + /* Needed for pam_unix_cred to chown files. */ + priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_CHOWN_SELF, NULL); + + /* Needed to access /var/adm/wtmpx. */ + priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_DAC_WRITE, NULL); } /* Setup priviledges before the user responds to the user prompt @@ -181,13 +187,53 @@ return PR_DECLINED(cmd); } +static priv_set_t* allocset(void) { + priv_set_t* ret; + + if ((ret = priv_allocset()) == NULL) { + pr_log_pri(PR_LOG_ERR, MOD_SOLARIS_PRIV_VERSION ": priv_allocset: %s", + strerror(errno)); + pr_signals_unblock(); + end_login(1); + } + + return ret; +} + +static void delset(priv_set_t *sp, const char *priv) { + if (priv_delset(sp, priv) != 0) { + pr_log_pri(PR_LOG_ERR, MOD_SOLARIS_PRIV_VERSION ": priv_delset: %s", + strerror(errno)); + pr_signals_unblock(); + end_login(1); + } +} + +static void addset(priv_set_t *sp, const char *priv) { + if (priv_addset(sp, priv) != 0) { + pr_log_pri(PR_LOG_ERR, MOD_SOLARIS_PRIV_VERSION ": priv_addset: %s", + strerror(errno)); + pr_signals_unblock(); + end_login(1); + } +} + +static void _setppriv(priv_op_t op, priv_ptype_t which, priv_set_t *set) { + if (setppriv(op, which, set) != 0) { + pr_log_pri(PR_LOG_ERR, MOD_SOLARIS_PRIV_VERSION ": setppriv: %s", + strerror(errno)); + pr_signals_unblock(); + end_login(1); + } +} + /* The POST_CMD handler for "PASS" is only called after PASS has * successfully completed, which means authentication is successful, * so we can "tweak" our root access down to almost nothing. */ MODRET solaris_priv_post_pass(cmd_rec *cmd) { int res = 0; - priv_set_t *p, *i; + priv_set_t *ps = NULL; if (!use_privs) return PR_DECLINED(cmd); @@ -203,56 +249,55 @@ * never need. */ - i = priv_allocset(); - priv_basicset(i); - priv_delset(i, PRIV_PROC_EXEC); - priv_delset(i, PRIV_PROC_FORK); - priv_delset(i, PRIV_PROC_INFO); - priv_delset(i, PRIV_PROC_SESSION); - setppriv(PRIV_SET, PRIV_INHERITABLE, i); + ps = allocset(); + priv_basicset(ps); + delset(ps, PRIV_PROC_EXEC); + delset(ps, PRIV_PROC_FORK); + delset(ps, PRIV_PROC_INFO); + delset(ps, PRIV_PROC_SESSION); + _setppriv(PRIV_SET, PRIV_INHERITABLE, ps); - p = priv_allocset(); - priv_basicset(p); + priv_basicset(ps); + + addset(ps, PRIV_NET_PRIVADDR); + addset(ps, PRIV_PROC_AUDIT); - priv_addset(p, PRIV_NET_PRIVADDR); - priv_addset(p, PRIV_PROC_AUDIT); - - priv_delset(p, PRIV_PROC_EXEC); - priv_delset(p, PRIV_PROC_FORK); - priv_delset(p, PRIV_PROC_INFO); - priv_delset(p, PRIV_PROC_SESSION); + delset(ps, PRIV_PROC_EXEC); + delset(ps, PRIV_PROC_FORK); + delset(ps, PRIV_PROC_INFO); + delset(ps, PRIV_PROC_SESSION); /* If the proftpd process is not running as root, but as user ftp, * then this is necessary in order to make the setreuid work. * Without this, the setreuid would fail. The PRIV_PROC_SETID privilege * is removed afterwards. */ - priv_addset(p, PRIV_PROC_SETID); + addset(ps, PRIV_PROC_SETID); /* Add any of the configurable privileges. */ if (solaris_priv_flags & PRIV_USE_FILE_CHOWN) - priv_addset(p, PRIV_FILE_CHOWN); + addset(ps, PRIV_FILE_CHOWN); if (solaris_priv_flags & PRIV_USE_FILE_CHOWN_SELF) - priv_addset(p, PRIV_FILE_CHOWN_SELF); + addset(ps, PRIV_FILE_CHOWN_SELF); if (solaris_priv_flags & PRIV_USE_DAC_READ) - priv_addset(p, PRIV_FILE_DAC_READ); + addset(ps, PRIV_FILE_DAC_READ); if (solaris_priv_flags & PRIV_USE_DAC_WRITE) - priv_addset(p, PRIV_FILE_DAC_WRITE); + addset(ps, PRIV_FILE_DAC_WRITE); if (solaris_priv_flags & PRIV_USE_DAC_SEARCH) - priv_addset(p, PRIV_FILE_DAC_SEARCH); + addset(ps, PRIV_FILE_DAC_SEARCH); if (solaris_priv_flags & PRIV_USE_FILE_OWNER) - priv_addset(p, PRIV_FILE_OWNER); + addset(ps, PRIV_FILE_OWNER); if (solaris_priv_flags & PRIV_DROP_FILE_WRITE) - priv_delset(p, PRIV_FILE_WRITE); + delset(ps, PRIV_FILE_WRITE); - res = setppriv(PRIV_SET, PRIV_PERMITTED, p); - res = setppriv(PRIV_SET, PRIV_EFFECTIVE, p); + _setppriv(PRIV_SET, PRIV_PERMITTED, ps); + _setppriv(PRIV_SET, PRIV_EFFECTIVE, ps); if (setreuid(session.uid, session.uid) == -1) { pr_log_pri(PR_LOG_ERR, MOD_SOLARIS_PRIV_VERSION ": setreuid: %s", @@ -262,21 +307,17 @@ } if (!(solaris_priv_flags & PRIV_USE_SETID)) { - priv_delset(p, PRIV_PROC_SETID); - res = setppriv(PRIV_SET, PRIV_PERMITTED, p); - res = setppriv(PRIV_SET, PRIV_EFFECTIVE, p); + delset(ps, PRIV_PROC_SETID); + _setppriv(PRIV_SET, PRIV_PERMITTED, ps); + _setppriv(PRIV_SET, PRIV_EFFECTIVE, ps); } + priv_freeset(ps); + pr_signals_unblock(); - if (res != -1) { - /* That's it! Disable all further id switching */ - session.disable_id_switching = TRUE; - - } else { - pr_log_pri(PR_LOG_NOTICE, MOD_SOLARIS_PRIV_VERSION ": attempt to configure " - "capabilities failed, reverting to normal operation"); - } + /* That's it! Disable all further id switching */ + session.disable_id_switching = TRUE; return PR_DECLINED(cmd); }