/* * Copyright (C) 2012-2013 Red Hat, Inc. All rights reserved. * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Authors: Roman Rakus */ #include #include "LMI_Account.h" #include #include #include #include #include #include #include #include #include #include "aux_lu.h" #include "macros.h" #include "globals.h" static const CMPIBroker* _cb = NULL; static void LMI_AccountInitialize() { } static CMPIStatus LMI_AccountCleanup( CMPIInstanceMI* mi, const CMPIContext* cc, CMPIBoolean term) { CMReturn(CMPI_RC_OK); } static CMPIStatus LMI_AccountEnumInstanceNames( CMPIInstanceMI* mi, const CMPIContext* cc, const CMPIResult* cr, const CMPIObjectPath* cop) { return KDefaultEnumerateInstanceNames( _cb, mi, cc, cr, cop); } static CMPIStatus LMI_AccountEnumInstances( CMPIInstanceMI* mi, const CMPIContext* cc, const CMPIResult* cr, const CMPIObjectPath* cop, const char** properties) { LMI_Account la; struct lu_context *luc = NULL; struct lu_error *error = NULL; GPtrArray *accounts = NULL; struct lu_ent *lue = NULL; size_t i; const char *nameSpace = KNameSpace(cop); const char *hostname = get_system_name(); char *uid = NULL; long last_change, min_lifetime, max_lifetime, warn, inactive, expire; time_t last_login; CMPIStatus *rc = NULL; const char *password = NULL; luc = lu_start(NULL, lu_user, NULL, NULL, lu_prompt_console_quiet, NULL, &error); if (!luc) { fprintf(stderr, "Error initializing: %s\n", lu_strerror(error)); exit(1); } accounts = lu_users_enumerate_full(luc, "*", &error); for (i = 0; (accounts != NULL) && (i < accounts->len); i++) { lue = g_ptr_array_index(accounts, i); LMI_Account_Init(&la, _cb, nameSpace); LMI_Account_Set_CreationClassName(&la, LMI_Account_ClassName); LMI_Account_Set_SystemName(&la, hostname); LMI_Account_Set_SystemCreationClassName(&la, get_system_creation_class_name()); LMI_Account_Set_Name(&la, aux_lu_get_str(lue, LU_USERNAME)); LMI_Account_Init_OrganizationName(&la, 1); /* XXX */ LMI_Account_Set_OrganizationName(&la, 0, ""); /* XXX */ /* Need to convert long int UID to the string */ asprintf(&uid, "%ld", aux_lu_get_long(lue, LU_UIDNUMBER)); LMI_Account_Set_UserID(&la, uid); free(uid); LMI_Account_Init_Host(&la, 1); LMI_Account_Set_Host(&la, 0, hostname); LMI_Account_Set_ElementName(&la, aux_lu_get_str(lue, LU_GECOS)); LMI_Account_Set_HomeDirectory(&la, aux_lu_get_str(lue, LU_HOMEDIRECTORY)); LMI_Account_Set_LoginShell(&la, aux_lu_get_str(lue, LU_LOGINSHELL)); last_change = aux_lu_get_long(lue, LU_SHADOWLASTCHANGE); if (last_change != SHADOW_VALUE_EMPTY) { LMI_Account_Set_PasswordLastChange(&la, CMNewDateTimeFromBinary(_cb, DAYSTOMS(last_change), false, rc)); } min_lifetime = aux_lu_get_long(lue, LU_SHADOWMIN); max_lifetime = aux_lu_get_long(lue, LU_SHADOWMAX); if (min_lifetime != SHADOW_VALUE_EMPTY) { LMI_Account_Set_PasswordPossibleChange(&la, CMNewDateTimeFromBinary(_cb, DAYSTOMS(min_lifetime), true, rc)); } if (max_lifetime != SHADOW_VALUE_EMPTY && max_lifetime != SHADOW_MAX_DISABLED) { LMI_Account_Set_PasswordExpiration(&la, CMNewDateTimeFromBinary(_cb, DAYSTOMS(max_lifetime), true, rc)); warn = aux_lu_get_long(lue, LU_SHADOWWARNING); LMI_Account_Set_PasswordExpirationWarning(&la, CMNewDateTimeFromBinary(_cb, DAYSTOMS(warn), true, rc)); inactive = aux_lu_get_long(lue, LU_SHADOWINACTIVE); if (inactive != SHADOW_VALUE_EMPTY) { LMI_Account_Set_PasswordInactivation(&la, CMNewDateTimeFromBinary(_cb, DAYSTOMS(inactive), true, rc)); } } else { LMI_Account_Null_PasswordExpiration(&la); LMI_Account_Null_PasswordExpirationWarning(&la); LMI_Account_Null_PasswordInactivation(&la); } expire = aux_lu_get_long(lue, LU_SHADOWEXPIRE); if (expire != SHADOW_VALUE_EMPTY) { LMI_Account_Set_AccountExpiration(&la, CMNewDateTimeFromBinary(_cb, DAYSTOMS(expire), false, rc)); } else { LMI_Account_Null_AccountExpiration(&la); } last_login = aux_utmp_latest(aux_lu_get_str(lue, LU_USERNAME)); if (last_login != SHADOW_VALUE_EMPTY) { LMI_Account_Set_LastLogin(&la, CMNewDateTimeFromBinary(_cb, STOMS(last_login), false, rc)); } password = aux_lu_get_str(lue, LU_SHADOWPASSWORD); LMI_Account_Init_UserPassword(&la, 1); LMI_Account_Set_UserPassword(&la, 0, password); /* Assume all passwords (encrypted or not) are in ascii encoding */ LMI_Account_Set_UserPasswordEncoding(&la, 2); KReturnInstance(cr, la); lu_ent_free(lue); } /* for */ if (accounts) { g_ptr_array_free(accounts, TRUE); } lu_end(luc); CMReturn(CMPI_RC_OK); } static CMPIStatus LMI_AccountGetInstance( CMPIInstanceMI* mi, const CMPIContext* cc, const CMPIResult* cr, const CMPIObjectPath* cop, const char** properties) { return KDefaultGetInstance( _cb, mi, cc, cr, cop, properties); } static CMPIStatus LMI_AccountCreateInstance( CMPIInstanceMI* mi, const CMPIContext* cc, const CMPIResult* cr, const CMPIObjectPath* cop, const CMPIInstance* ci) { CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); } /* Need better view on set date time properties */ typedef struct _date_time_prop { long value; bool null; /* True if property is set to null - has no value */ bool interval; /* True if value is interval */ } date_time_prop; static CMPIStatus LMI_AccountModifyInstance( CMPIInstanceMI* mi, const CMPIContext* cc, const CMPIResult* cr, const CMPIObjectPath* cop, const CMPIInstance* ci, const char** properties) { /* TODO: * * Allow to modify the following: * Set up account expiration * Set up password expiration */ const char* value = NULL, *password = NULL; CMPIString* vs = NULL; CMPIArray* ar = NULL; int arsize;/* used for password */ CMPIData data; struct lu_context *luc = NULL; struct lu_ent *lue = NULL; struct lu_error *error = NULL; GValue val; long last_change; date_time_prop expiration, warning, inactive_password, inactive_account; date_time_prop possible_change; LMI_Account la; LMI_Account_InitFromObjectPath(&la, _cb, cop); luc = lu_start(NULL, lu_user, NULL, NULL, lu_prompt_console_quiet, NULL, &error); if (!luc) { fprintf(stderr, "Error initializing: %s\n", lu_strerror(error)); exit(1); } lue = lu_ent_new(); if (!lu_user_lookup_name(luc, la.Name.chars, lue, &error)) { lu_end(luc); lu_ent_free(lue); KReturn2(_cb, ERR_NOT_FOUND, "User %s not found: %s", la.Name.chars, lu_strerror(error)); } data = ci->ft->getProperty(ci, "UserPassword", NULL); ar = data.value.array; if (ar && (arsize = ar->ft->getSize(ar, NULL) > 0)) { vs = ar->ft->getElementAt(ar, 0, NULL).value.string; value = vs->ft->getCharPtr(vs, NULL); password = aux_lu_get_str(lue, LU_SHADOWPASSWORD); if (strcmp(password, value) != 0) { if (!lu_user_setpass(luc, lue, value, TRUE, &error)) { lu_end(luc); lu_ent_free(lue); KReturn2(_cb, ERR_FAILED, "Error setting password: %s", lu_strerror(error)); } } } else { if (!lu_user_removepass(luc, lue, &error)) { lu_end(luc); lu_ent_free(lue); KReturn2(_cb, ERR_FAILED, "Error removing password: %s", lu_strerror(error)); } } #define PARAMSTR(ATTR, VAR)\ g_value_set_string(&val, (VAR));\ lu_ent_clear(lue, (ATTR));\ lu_ent_add(lue, (ATTR), &val);\ #define PARAMLONG(ATTR, VAR)\ if (!(VAR).null) {\ g_value_set_long(&val, (VAR).value);\ lu_ent_clear(lue, (ATTR));\ lu_ent_add(lue, (ATTR), &val);}\ /* This macro will get property named NAME and save it into `value' variable */ #define GETSTRVALUE(NAME)\ data = ci->ft->getProperty(ci, (NAME), NULL);\ vs = data.value.string;\ value = vs->ft->getCharPtr(vs, NULL);\ #define GETDATEVALUE(NAME, VAR)\ (VAR).null = CMGetProperty(ci, (NAME), NULL).state == CMPI_nullValue;\ if (!(VAR).null)\ {\ (VAR).interval = CMIsInterval(\ CMGetProperty(ci, (NAME), NULL).value.dateTime, NULL); \ (VAR).value = MSTODAYS(CMGetBinaryFormat(\ CMGetProperty(ci, (NAME), NULL).value.dateTime, NULL));\ }\ /* First string values */ memset(&val, 0, sizeof(val)); g_value_init(&val, G_TYPE_STRING); GETSTRVALUE("ElementName"); PARAMSTR(LU_GECOS, value); GETSTRVALUE("HomeDirectory"); PARAMSTR(LU_HOMEDIRECTORY, value); GETSTRVALUE("LoginShell"); PARAMSTR(LU_LOGINSHELL, value); /* Now long values */ memset(&val, 0, sizeof(val)); g_value_init(&val, G_TYPE_LONG); last_change = aux_lu_get_long(lue, LU_SHADOWLASTCHANGE); #define FAIL(msg) \ lu_end(luc); \ lu_ent_free(lue); \ KReturn2(_cb, ERR_FAILED, msg); GETDATEVALUE("PasswordExpiration", expiration); if (!expiration.null && !expiration.interval) { if ((expiration.value -= last_change) < 0) { FAIL("Wrong property setting, " "PasswordExpiration must be later than " "PasswordLastChange\n"); } } GETDATEVALUE("PasswordExpirationWarning", warning); if (!warning.null && !warning.interval) { if (expiration.null) { FAIL("Wrong property setting, " "PasswordExpiration must be set if you want to set " "PasswordExpirationWarning as time of date\n"); } warning.value = last_change + expiration.value - warning.value; if (warning.value < 0) { FAIL("Wrong property setting, " "PasswordExpirationWarning must be earlier than " "PasswordExpiration\n"); } } GETDATEVALUE("PasswordInactivation", inactive_password); if (!inactive_password.null && !inactive_password.interval) { if (expiration.null) { FAIL("Wrong property setting, " "PasswordExpiration must be set if you want to set " "PasswordInactivation as time of date\n"); } inactive_password.value -= last_change + expiration.value; if (inactive_password.value < 0) { FAIL("Wrong property setting, " "PasswordInactivation must be later than " "PasswordExpiration\n"); } } GETDATEVALUE("PasswordPossibleChange", possible_change); if (!possible_change.null && !possible_change.interval) { if ((possible_change.value -= last_change) < 0) { FAIL("Wrong property setting, " "PasswordPossibleChange must be later than " "PasswordLastChange\n"); } } GETDATEVALUE("AccountExpiration", inactive_account); if (!inactive_account.null && inactive_account.interval) { FAIL("Wrong property setting, " "AccountExpiration must be set as interval\n"); } #undef FAIL PARAMLONG(LU_SHADOWMIN, possible_change); PARAMLONG(LU_SHADOWMAX, expiration); PARAMLONG(LU_SHADOWWARNING, warning); PARAMLONG(LU_SHADOWINACTIVE, inactive_password); PARAMLONG(LU_SHADOWEXPIRE, inactive_account); #undef PARAMSTR #undef PARAMLONG #undef GETSTRVALUE #undef GETDATEVALUE g_value_unset(&val); if (!lu_user_modify(luc, lue, &error)) { lu_end(luc); lu_ent_free(lue); KReturn2(_cb, ERR_FAILED, "User modification failed: %s", lu_strerror(error)); } lu_ent_free(lue); lu_end(luc); CMReturn(CMPI_RC_OK); } static CMPIStatus LMI_AccountDeleteInstance( CMPIInstanceMI* mi, const CMPIContext* cc, const CMPIResult* cr, const CMPIObjectPath* cop) { LMI_Account acc; const char* username = NULL, *home = NULL; struct lu_context *luc = NULL; struct lu_error *error = NULL; struct lu_ent *lue = NULL; LMI_Account_InitFromObjectPath(&acc, _cb, cop); username = acc.Name.chars; luc = lu_start(NULL, 0, NULL, NULL, lu_prompt_console_quiet, NULL, &error); if (!luc) { fprintf(stderr, "Error initializing: %s\n", lu_strerror(error)); exit(1); } lue = lu_ent_new(); if (!lu_user_lookup_name(luc, username, lue, &error)) { lu_ent_free(lue); lu_end(luc); KReturn2(_cb, ERR_NOT_FOUND, "Non existing user: %s\n", username); } home = aux_lu_get_str(lue, LU_HOMEDIRECTORY); /* Be really safe here, it can delete ANY directory */ if (!lu_homedir_remove(home, &error)) { lu_ent_free(lue); lu_end(luc); KReturn2(_cb, ERR_FAILED, "User's homedir %s could not be deleted: %s\n", home, lu_strerror(error)); } if (!lu_user_delete(luc, lue, &error)) { lu_ent_free(lue); lu_end(luc); KReturn2(_cb, ERR_FAILED, "User %s could not be deleted: %s\n", username, lu_strerror(error)); } lu_ent_free(lue); lu_end(luc); CMReturn(CMPI_RC_OK); } static CMPIStatus LMI_AccountExecQuery( CMPIInstanceMI* mi, const CMPIContext* cc, const CMPIResult* cr, const CMPIObjectPath* cop, const char* lang, const char* query) { CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); } CMInstanceMIStub( LMI_Account, LMI_Account, _cb, LMI_AccountInitialize()) static CMPIStatus LMI_AccountMethodCleanup( CMPIMethodMI* mi, const CMPIContext* cc, CMPIBoolean term) { CMReturn(CMPI_RC_OK); } static CMPIStatus LMI_AccountInvokeMethod( CMPIMethodMI* mi, const CMPIContext* cc, const CMPIResult* cr, const CMPIObjectPath* cop, const char* meth, const CMPIArgs* in, CMPIArgs* out) { return LMI_Account_DispatchMethod( _cb, mi, cc, cr, cop, meth, in, out); } CMMethodMIStub( LMI_Account, LMI_Account, _cb, LMI_AccountInitialize()) KUint32 LMI_Account_RequestStateChange( const CMPIBroker* cb, CMPIMethodMI* mi, const CMPIContext* context, const LMI_AccountRef* self, const KUint16* RequestedState, KRef* Job, const KDateTime* TimeoutPeriod, CMPIStatus* status) { KUint32 result = KUINT32_INIT; KSetStatus(status, ERR_NOT_SUPPORTED); return result; } KONKRET_REGISTRATION( "root/cimv2", "LMI_Account", "LMI_Account", "instance method")