| /* | 
 |  * QEMU PAM authorization driver | 
 |  * | 
 |  * Copyright (c) 2018 Red Hat, Inc. | 
 |  * | 
 |  * This library is free software; you can redistribute it and/or | 
 |  * modify it under the terms of the GNU Lesser General Public | 
 |  * License as published by the Free Software Foundation; either | 
 |  * version 2.1 of the License, or (at your option) any later version. | 
 |  * | 
 |  * This library is distributed in the hope that it will be useful, | 
 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 |  * Lesser General Public License for more details. | 
 |  * | 
 |  * You should have received a copy of the GNU Lesser General Public | 
 |  * License along with this library; if not, see <http://www.gnu.org/licenses/>. | 
 |  * | 
 |  */ | 
 |  | 
 | #include "qemu/osdep.h" | 
 | #include "authz/pamacct.h" | 
 | #include "trace.h" | 
 | #include "qemu/module.h" | 
 | #include "qom/object_interfaces.h" | 
 |  | 
 | #include <security/pam_appl.h> | 
 |  | 
 |  | 
 | static bool qauthz_pam_is_allowed(QAuthZ *authz, | 
 |                                   const char *identity, | 
 |                                   Error **errp) | 
 | { | 
 |     QAuthZPAM *pauthz = QAUTHZ_PAM(authz); | 
 |     const struct pam_conv pam_conversation = { 0 }; | 
 |     pam_handle_t *pamh = NULL; | 
 |     int ret; | 
 |  | 
 |     trace_qauthz_pam_check(authz, identity, pauthz->service); | 
 |     ret = pam_start(pauthz->service, | 
 |                     identity, | 
 |                     &pam_conversation, | 
 |                     &pamh); | 
 |     if (ret != PAM_SUCCESS) { | 
 |         error_setg(errp, "Unable to start PAM transaction: %s", | 
 |                    pam_strerror(NULL, ret)); | 
 |         return false; | 
 |     } | 
 |  | 
 |     ret = pam_acct_mgmt(pamh, PAM_SILENT); | 
 |     pam_end(pamh, ret); | 
 |     if (ret != PAM_SUCCESS) { | 
 |         error_setg(errp, "Unable to authorize user '%s': %s", | 
 |                    identity, pam_strerror(pamh, ret)); | 
 |         return false; | 
 |     } | 
 |  | 
 |     return true; | 
 | } | 
 |  | 
 |  | 
 | static void | 
 | qauthz_pam_prop_set_service(Object *obj, | 
 |                             const char *service, | 
 |                             Error **errp G_GNUC_UNUSED) | 
 | { | 
 |     QAuthZPAM *pauthz = QAUTHZ_PAM(obj); | 
 |  | 
 |     g_free(pauthz->service); | 
 |     pauthz->service = g_strdup(service); | 
 | } | 
 |  | 
 |  | 
 | static char * | 
 | qauthz_pam_prop_get_service(Object *obj, | 
 |                             Error **errp G_GNUC_UNUSED) | 
 | { | 
 |     QAuthZPAM *pauthz = QAUTHZ_PAM(obj); | 
 |  | 
 |     return g_strdup(pauthz->service); | 
 | } | 
 |  | 
 |  | 
 | static void | 
 | qauthz_pam_complete(UserCreatable *uc, Error **errp) | 
 | { | 
 |     QAuthZPAM *pauthz = QAUTHZ_PAM(uc); | 
 |  | 
 |     if (!pauthz->service) { | 
 |         error_setg(errp, "The 'service' property must be set"); | 
 |         return; | 
 |     } | 
 | } | 
 |  | 
 |  | 
 | static void | 
 | qauthz_pam_finalize(Object *obj) | 
 | { | 
 |     QAuthZPAM *pauthz = QAUTHZ_PAM(obj); | 
 |  | 
 |     g_free(pauthz->service); | 
 | } | 
 |  | 
 |  | 
 | static void | 
 | qauthz_pam_class_init(ObjectClass *oc, const void *data) | 
 | { | 
 |     UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); | 
 |     QAuthZClass *authz = QAUTHZ_CLASS(oc); | 
 |  | 
 |     ucc->complete = qauthz_pam_complete; | 
 |     authz->is_allowed = qauthz_pam_is_allowed; | 
 |  | 
 |     object_class_property_add_str(oc, "service", | 
 |                                   qauthz_pam_prop_get_service, | 
 |                                   qauthz_pam_prop_set_service); | 
 | } | 
 |  | 
 |  | 
 | QAuthZPAM *qauthz_pam_new(const char *id, | 
 |                           const char *service, | 
 |                           Error **errp) | 
 | { | 
 |     return QAUTHZ_PAM( | 
 |         object_new_with_props(TYPE_QAUTHZ_PAM, | 
 |                               object_get_objects_root(), | 
 |                               id, errp, | 
 |                               "service", service, | 
 |                               NULL)); | 
 | } | 
 |  | 
 |  | 
 | static const TypeInfo qauthz_pam_info = { | 
 |     .parent = TYPE_QAUTHZ, | 
 |     .name = TYPE_QAUTHZ_PAM, | 
 |     .instance_size = sizeof(QAuthZPAM), | 
 |     .instance_finalize = qauthz_pam_finalize, | 
 |     .class_init = qauthz_pam_class_init, | 
 |     .interfaces = (const InterfaceInfo[]) { | 
 |         { TYPE_USER_CREATABLE }, | 
 |         { } | 
 |     } | 
 | }; | 
 |  | 
 |  | 
 | static void | 
 | qauthz_pam_register_types(void) | 
 | { | 
 |     type_register_static(&qauthz_pam_info); | 
 | } | 
 |  | 
 |  | 
 | type_init(qauthz_pam_register_types); |