fail authentication for single group name which cannot be converted to sid
[samba.git] / nsswitch / pam_winbind.c
index 7d5b70e1bdf56f80217a74008595b4ced6c71c6b..cd5e7ba206ee25c68bcb71fefde5e076da568b29 100644 (file)
@@ -10,6 +10,8 @@
    <sopwith@redhat.com> (see copyright below for full details)
 */
 
+#define UID_WRAPPER_NOT_REPLACE
+
 #include "pam_winbind.h"
 
 static int wbc_error_to_pam_error(wbcErr status)
@@ -162,25 +164,6 @@ static inline void textdomain_init(void)
 #endif
 
 
-/*
- * Work around the pam API that has functions with void ** as parameters
- * These lead to strict aliasing warnings with gcc.
- */
-static int _pam_get_item(const pam_handle_t *pamh,
-                        int item_type,
-                        const void *_item)
-{
-       const void **item = (const void **)_item;
-       return pam_get_item(pamh, item_type, item);
-}
-static int _pam_get_data(const pam_handle_t *pamh,
-                        const char *module_data_name,
-                        const void *_data)
-{
-       const void **data = (const void **)_data;
-       return pam_get_data(pamh, module_data_name, data);
-}
-
 /* some syslogging */
 
 #ifdef HAVE_PAM_VSYSLOG
@@ -200,7 +183,7 @@ static void _pam_log_int(const pam_handle_t *pamh,
        char *format2 = NULL;
        const char *service;
 
-       _pam_get_item(pamh, PAM_SERVICE, &service);
+       pam_get_item(pamh, PAM_SERVICE, (const void **) &service);
 
        format2 = (char *)malloc(strlen(MODULE_NAME)+strlen(format)+strlen(service)+5);
        if (format2 == NULL) {
@@ -347,6 +330,21 @@ static void _pam_log_state_datum(struct pwb_context *ctx,
 #define _PAM_LOG_STATE_ITEM_PASSWORD(ctx, item_type) \
        _pam_log_state_datum(ctx, item_type, #item_type, \
                             _LOG_PASSWORD_AS_STRING)
+/*
+ * wrapper to preserve old behaviour of iniparser which ignored
+ * key values that had no value assigned like
+ *    key =
+ * for a key like above newer iniparser will return a zero-length
+ * string, previously iniparser would return NULL
+ */
+static char *iniparser_getstring_nonempty(dictionary *d, char *key, char *def)
+{
+       char *ret = iniparser_getstring(d, key, def);
+       if (ret && strlen(ret) == 0) {
+               ret = NULL;
+       }
+       return ret;
+}
 
 static void _pam_log_state(struct pwb_context *ctx)
 {
@@ -435,13 +433,13 @@ static int _pam_parse(const pam_handle_t *pamh,
                ctrl |= WINBIND_SILENT;
        }
 
-       if (iniparser_getstr(d, discard_const_p(char, "global:krb5_ccache_type")) != NULL) {
+       if (iniparser_getstring_nonempty(d, discard_const_p(char, "global:krb5_ccache_type"), NULL) != NULL) {
                ctrl |= WINBIND_KRB5_CCACHE_TYPE;
        }
 
-       if ((iniparser_getstr(d, discard_const_p(char, "global:require-membership-of"))
+       if ((iniparser_getstring_nonempty(d, discard_const_p(char, "global:require-membership-of"), NULL)
             != NULL) ||
-           (iniparser_getstr(d, discard_const_p(char, "global:require_membership_of"))
+           (iniparser_getstring_nonempty(d, discard_const_p(char, "global:require_membership_of"), NULL)
             != NULL)) {
                ctrl |= WINBIND_REQUIRED_MEMBERSHIP;
        }
@@ -536,7 +534,7 @@ static int _pam_winbind_init_context(pam_handle_t *pamh,
        textdomain_init();
 #endif
 
-       r = TALLOC_ZERO_P(NULL, struct pwb_context);
+       r = talloc_zero(NULL, struct pwb_context);
        if (!r) {
                return PAM_BUF_ERR;
        }
@@ -643,7 +641,7 @@ static int converse(const pam_handle_t *pamh,
        int retval;
        struct pam_conv *conv;
 
-       retval = _pam_get_item(pamh, PAM_CONV, &conv);
+       retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv);
        if (retval == PAM_SUCCESS) {
                retval = conv->conv(nargs,
                                    (const struct pam_message **)message,
@@ -810,13 +808,11 @@ static bool _pam_winbind_change_pwd(struct pwb_context *ctx)
 {
        struct pam_message msg, *pmsg;
        struct pam_response *resp = NULL;
-       const char *prompt;
        int ret;
        bool retval = false;
-       prompt = _("Do you want to change your password now?");
        pmsg = &msg;
        msg.msg_style = PAM_RADIO_TYPE;
-       msg.msg = prompt;
+       msg.msg = _("Do you want to change your password now?");
        ret = converse(ctx->pamh, 1, &pmsg, &resp);
        if (resp == NULL) {
                if (ret == PAM_SUCCESS) {
@@ -829,7 +825,7 @@ static bool _pam_winbind_change_pwd(struct pwb_context *ctx)
        }
        _pam_log(ctx, LOG_CRIT, "Received [%s] reply from application.\n", resp->resp);
 
-       if (strcasecmp(resp->resp, "yes") == 0) {
+       if ((resp->resp != NULL) && (strcasecmp(resp->resp, "yes") == 0)) {
                retval = true;
        }
 
@@ -1047,15 +1043,9 @@ static bool safe_append_string(char *dest,
                               const char *src,
                               int dest_buffer_size)
 {
-       int dest_length = strlen(dest);
-       int src_length = strlen(src);
-
-       if (dest_length + src_length + 1 > dest_buffer_size) {
-               return false;
-       }
-
-       memcpy(dest + dest_length, src, src_length + 1);
-       return true;
+       size_t len;
+       len = strlcat(dest, src, dest_buffer_size);
+       return (len < dest_buffer_size);
 }
 
 /**
@@ -1182,6 +1172,12 @@ static bool winbind_name_list_to_sid_string_list(struct pwb_context *ctx,
                _make_remark_format(ctx, PAM_TEXT_INFO, _("Cannot convert group %s "
                                "to sid, please contact your administrator to see "
                                "if group %s is valid."), search_location, search_location);
+
+               /* If no valid groups were converted we should fail outright */
+               if (name_list != NULL && strlen(sid_list_buffer) == 0) {
+                       result = false;
+                       goto out;
+               }
                /*
                 * The lookup of the last name failed..
                 * It results in require_member_of_sid ends with ','
@@ -1944,7 +1940,7 @@ static int winbind_chauthtok_request(struct pwb_context *ctx,
        }
 
        params.account_name             = user;
-       params.level                    = WBC_AUTH_USER_LEVEL_PLAIN;
+       params.level                    = WBC_CHANGE_PASSWORD_LEVEL_PLAIN;
        params.old_password.plaintext   = oldpass;
        params.new_password.plaintext   = newpass;
        params.flags                    = flags;
@@ -2062,6 +2058,9 @@ static int valid_user(struct pwb_context *ctx,
 
        switch (wbc_status) {
                case WBC_ERR_UNKNOWN_USER:
+               /* match other insane libwbclient return codes */
+               case WBC_ERR_WINBIND_NOT_AVAILABLE:
+               case WBC_ERR_DOMAIN_NOT_FOUND:
                        return 1;
                case WBC_ERR_SUCCESS:
                        return 0;
@@ -2118,7 +2117,9 @@ static int _winbind_read_password(struct pwb_context *ctx,
 
        if (on(WINBIND_TRY_FIRST_PASS_ARG, ctrl) ||
            on(WINBIND_USE_FIRST_PASS_ARG, ctrl)) {
-               retval = _pam_get_item(ctx->pamh, authtok_flag, &item);
+               retval = pam_get_item(ctx->pamh,
+                                     authtok_flag,
+                                     (const void **) &item);
                if (retval != PAM_SUCCESS) {
                        /* very strange. */
                        _pam_log(ctx, LOG_ALERT,
@@ -2226,7 +2227,7 @@ static int _winbind_read_password(struct pwb_context *ctx,
        retval = pam_set_item(ctx->pamh, authtok_flag, token);
        _pam_delete(token);     /* clean it up */
        if (retval != PAM_SUCCESS ||
-           (retval = _pam_get_item(ctx->pamh, authtok_flag, &item)) != PAM_SUCCESS) {
+           (retval = pam_get_item(ctx->pamh, authtok_flag, (const void **) &item)) != PAM_SUCCESS) {
 
                _pam_log(ctx, LOG_CRIT, "error manipulating password");
                return retval;
@@ -2276,7 +2277,7 @@ static const char *get_conf_item_string(struct pwb_context *ctx,
                        goto out;
                }
 
-               parm_opt = iniparser_getstr(ctx->dict, key);
+               parm_opt = iniparser_getstring_nonempty(ctx->dict, key, NULL);
                TALLOC_FREE(key);
 
                _pam_log_debug(ctx, LOG_INFO, "CONFIG file: %s '%s'\n",
@@ -2444,7 +2445,7 @@ static char* winbind_upn_to_username(struct pwb_context *ctx,
                return NULL;
        }
 
-       return talloc_asprintf(ctx, "%s\\%s", domain, name);
+       return talloc_asprintf(ctx, "%s%c%s", domain, sep, name);
 }
 
 static int _pam_delete_cred(pam_handle_t *pamh, int flags,
@@ -2731,9 +2732,10 @@ out:
                _pam_free_data_info3(pamh);
        }
 
-       _PAM_LOG_FUNCTION_LEAVE("pam_sm_authenticate", ctx, retval);
-
-       TALLOC_FREE(ctx);
+       if (ctx != NULL) {
+               _PAM_LOG_FUNCTION_LEAVE("pam_sm_authenticate", ctx, retval);
+               TALLOC_FREE(ctx);
+       }
 
        return retval;
 }
@@ -2796,7 +2798,7 @@ int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
 {
        const char *username;
        int ret = PAM_USER_UNKNOWN;
-       void *tmp = NULL;
+       const char *tmp = NULL;
        struct pwb_context *ctx = NULL;
 
        ret = _pam_winbind_init_context(pamh, flags, argc, argv, &ctx);
@@ -2837,7 +2839,7 @@ int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
                pam_get_data(pamh, PAM_WINBIND_NEW_AUTHTOK_REQD,
                             (const void **)&tmp);
                if (tmp != NULL) {
-                       ret = atoi((const char *)tmp);
+                       ret = atoi(tmp);
                        switch (ret) {
                        case PAM_AUTHTOK_EXPIRED:
                                /* fall through, since new token is required in this case */
@@ -2963,8 +2965,8 @@ static bool _pam_require_krb5_auth_after_chauthtok(struct pwb_context *ctx,
        char *new_authtok_reqd_during_auth = NULL;
        struct passwd *pwd = NULL;
 
-       _pam_get_data(ctx->pamh, PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH,
-                     &new_authtok_reqd_during_auth);
+       pam_get_data(ctx->pamh, PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH,
+                     (const void **) &new_authtok_reqd_during_auth);
        pam_set_data(ctx->pamh, PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH,
                     NULL, NULL);
 
@@ -2995,7 +2997,8 @@ int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
 
        /* <DO NOT free() THESE> */
        const char *user;
-       char *pass_old, *pass_new;
+       const char *pass_old;
+       const char *pass_new;
        /* </DO NOT free() THESE> */
 
        char *Announce;
@@ -3118,7 +3121,7 @@ int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
                 * get the old token back.
                 */
 
-               ret = _pam_get_item(pamh, PAM_OLDAUTHTOK, &pass_old);
+               ret = pam_get_item(pamh, PAM_OLDAUTHTOK, (const void **) &pass_old);
 
                if (ret != PAM_SUCCESS) {
                        _pam_log(ctx, LOG_NOTICE,
@@ -3168,8 +3171,8 @@ int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
                 * By reaching here we have approved the passwords and must now
                 * rebuild the password database file.
                 */
-               _pam_get_data(pamh, PAM_WINBIND_PWD_LAST_SET,
-                             &pwdlastset_update);
+               pam_get_data(pamh, PAM_WINBIND_PWD_LAST_SET,
+                            (const void **) &pwdlastset_update);
 
                /*
                 * if cached creds were enabled, make sure to set the