/* users.c -- eurephiadm command - User Account Management * * GPLv2 only - Copyright (C) 2008 - 2010 * David Sommerseth * * 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 the Free Software Foundation; version 2 * of the License. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ /** * @file users.c * @author David Sommerseth * @date 2008-12-01 * * @brief eurephiadm users command. User account management command. * */ #include #include #include #include #include #ifdef HAVE_LIBXML2 #include #include #endif #define MODULE "eurephia::Users" /**< Need to define the active module before including argparser.h */ #include #include #include #include #include #include #include #include #include #include "../argparser.h" #include "../get_console_input.h" #include "../parse_certificate_files.h" #include "../xsltparser.h" /** * Forward declaration of a function already found in certificates.c */ int register_certificate(eurephiaCTX *ctx, int depth, const char *digest, const char *cname, const char *org, const char *email); /** * Help screens for the users command * * @param page which help screen to display */ void display_users_help(int page) { printf("\n%s -- Administer user accounts\n\n", MODULE); switch( page ) { case 'l': printf("The list mode can accept one parameter:\n\n" " -S | --sort Decide the sort order of the user list\n" "\n" "Available sort keys are: uid, username, activated, deactivated and lastaccess\n\n"); break; case 's': printf("The show mode shows more information about a user account.\n" "One of the following arguments are required:\n\n" " -i | --uid Numeric user ID\n" " -u | --username User name\n" "\n" "Optional arguments are:\n\n" " -l | --lastlog Show users lastlog entries\n" " -L | --lastlog-details Show a more verbose lastlog\n" " -a | --attempts Show users failed attempts and blacklisting\n" " -b | --blacklist Alias for --attempts\n" "\n"); break; case 'a': printf("The activate mode activates an account which not activated or deactivated.\n" "One of the following arguments are required:\n\n" " -i | --uid Numeric user ID\n" " -u | --username User name\n\n"); break; case 'd': printf("The deactivate mode deactivates a user account.\n" "One of the following arguments are required:\n\n" " -i | --uid Numeric user ID\n" " -u | --username User name\n\n"); break; case 'A': printf("The add user mode registers a new user account.\n" "Both of the following arguments are required:\n\n" " -u | --username User name to use for the new account (required)\n" " -P | --password Assign a new password via the command line.\n\n" "To register this new account against a certificate you can use the\n" "following arguments. These arguments cannot be used together.\n\n" " -C | --certid Use already registered certificate, identified by certid.\n" " -D | --digest Use already registered certificate, identified by digest.\n" " -c | --certfile Use the given certificate file and register it along with\n" " the account.\n" " -2 | --pkcs12 Certificate file is using the PKCS#12 format.\n\n"); break; case 'D': printf("The delete user mode will delete a user account from the database.\n" "One of the following arguments are required:\n\n" " -i | --uid Numeric user ID\n" " -u | --username User name\n\n"); break; case 'p': printf("The change password mode is used for changing password for other\n" "persons than yourself.\n\n" "One of the following arguments are required:\n\n" " -i | --uid Numeric user ID\n" " -u | --username User name\n\n"); break; default: printf("Available modes:\n" " -l | --list List all user accounts\n" " -s | --show Show user account details\n" " -a | --activate Activate a user account\n" " -d | --deactivate Deactivate a user account\n" " -A | --add Add a new user account\n" " -D | --delete Delete a user account\n" " -p | --password Change password on a users account\n" " -h | --help Further help for these modes\n\n"); break; } } /** * Help screen wrapper for the users help function. * * @param ctx eurephiaCTX * @param sess eurephiaSESSION of the current logged in user * @param cfg eurephiaVALUES struct of the current configuration * @param argc argument count for the eurephiadm command * @param argv argument table for the eurephiadm command * * @return returns 0 on success, otherwise 1. */ int help_Users2(eurephiaCTX *ctx, eurephiaSESSION *sess, eurephiaVALUES *cfg, int argc, char **argv) { e_options helpargs[] = { {"--list", "-l", 0}, {"--show", "-s", 0}, {"--activate", "-a", 0}, {"--deactivate", "-d", 0}, {"--add", "-A", 0}, {"--delete", "-D", 0}, {"--password", "-p", 0}, {NULL, NULL, 0} }; int i = 1; display_users_help(eurephia_getopt(&i, argc, argv, helpargs)); return 0; } /** * Help screen wrapper. Used by cmd_Help() */ void help_Users() { display_users_help(0); } /** * users list mode. Lists all registered users. * * @param ctx eurephiaCTX * @param sess eurephiaSESSION of the current logged in user * @param cfg eurephiaVALUES struct of the current configuration * @param argc argument count for the eurephiadm command * @param argv argument table for the eurephiadm command * * @return returns 0 on success, otherwise 1. */ int list_users(eurephiaCTX *ctx, eurephiaSESSION *sess, eurephiaVALUES *cfg, int argc, char **argv) { xmlDoc *qrydoc = NULL, *userlist = NULL; xmlNode *qry_n = NULL, *fmap_n = NULL; int i = 0, rc = 0; char *sortkeys = NULL; const char *xsltparams[] = {"view", "'userlist'", NULL}; e_options listargs[] = { {"--sort", "-S", 1}, {"--help", "-h", 0}, {NULL, NULL, 0} }; assert((ctx != NULL) && (ctx->dbc != NULL) && (ctx->dbc->config != NULL)); // Parse arguments for( i = 1; i < argc; i++ ) { switch( eurephia_getopt(&i, argc, argv, listargs) ) { case 'S': sortkeys = optargs[0]; i++; break; case 'h': display_users_help('l'); return 0; default: return 1; } } // Create a query document eurephiaXML_CreateDoc(ctx, 1, "UserAccount", &qrydoc, &qry_n); assert( (qrydoc != NULL) && (qry_n != NULL) ); xmlNewProp(qry_n, (xmlChar *) "mode", (xmlChar *) "view"); xmlNewChild(qry_n, NULL, (xmlChar *) "sortkeys", (xmlChar *)sortkeys); xmlNewChild(qry_n, NULL, (xmlChar *) "extractFlags", (xmlChar *) "1"); fmap_n = xmlNewChild(qry_n, NULL, (xmlChar *) "fieldMapping", NULL); assert( fmap_n != NULL ); xmlNewProp(fmap_n, (xmlChar *) "table", (xmlChar *) "users"); // Retrieve the user list - and display it userlist = eDBadminUserAccount(ctx, qrydoc); if( eurephiaXML_IsResultMsg(ctx, userlist) ) { eurephiaRESULT *res = eurephiaXML_ParseResultMsg(ctx, userlist); if( res->resultType == exmlERROR ) { fprintf(stderr, "%s: %s\n", MODULE, res->message); rc = 1; } else { rc = 2; } free_nullsafe(ctx, res); } else { xslt_print_xmldoc(stdout, cfg, userlist, "users.xsl", xsltparams); rc = 0; } xmlFreeDoc(userlist); xmlFreeDoc(qrydoc); return rc; } /** * users show mode. Show account information for a particular user * * @param ctx eurephiaCTX * @param sess eurephiaSESSION of the current logged in user * @param cfg eurephiaVALUES struct of the current configuration * @param argc argument count for the eurephiadm command * @param argv argument table for the eurephiadm command * * @return returns 0 on success, otherwise 1. */ int show_user(eurephiaCTX *ctx, eurephiaSESSION *sess, eurephiaVALUES *cfg, int argc, char **argv) { int i, crit_set = 0, lastlog_verb = 0; long int show_info = USERINFO_user | USERINFO_certs; xmlDoc *user_xml = NULL, *srch_xml = NULL; xmlNode *srch_root = NULL, *fmap_n = NULL; xmlChar flags[34]; #ifdef FIREWALL const char *xsltparams[] = {"view", NULL, "firewall", "'1'", "view_digest", "'0'", NULL}; #else const char *xsltparams[] = {"view", NULL, "firewall", "'0'", "view_digest", "'0'", NULL}; #endif e_options activargs[] = { {"--uid", "-i", 1}, {"--username", "-u", 1}, {"--lastlog", "-l", 0}, {"--lastlog-details", "-L", 0}, {"--attempts", "-a", 0}, {"--blacklist", "-b", 0}, // Alias for -a | --attempts {"--help", "-h", 0}, {NULL, NULL, 0} }; assert((ctx != NULL) && (ctx->dbc != NULL) && (ctx->dbc->config != NULL)); // Create a UserAccount query XML document eurephiaXML_CreateDoc(ctx, 1, "UserAccount", &srch_xml, &srch_root); xmlNewProp(srch_root, (xmlChar*) "mode", (xmlChar *) "view"); // Setup the fieldMapping - to narrow the search fmap_n = xmlNewChild(srch_root, NULL, (xmlChar *) "fieldMapping", NULL); xmlNewProp(fmap_n, (xmlChar *) "table", (xmlChar *)"users"); // Argument parsing crit_set = 0; for( i = 1; i < argc; i++ ) { switch( eurephia_getopt(&i, argc, argv, activargs) ) { case 'i': if( atoi_nullsafe(optargs[0]) == 0 ) { fprintf(stderr, "%s: Invalid user id\n", MODULE); return 1; } xmlNewChild(fmap_n, NULL, (xmlChar *)"uid", (xmlChar *) optargs[0]); crit_set++; break; case 'u': if( strlen_nullsafe(optargs[0]) < 3 ) { fprintf(stderr, "%s: User name too short\n", MODULE); return 1; } xmlNewChild(fmap_n, NULL, (xmlChar *)"username", (xmlChar *)optargs[0]); crit_set++; break; case 'a': case 'b': show_info = USERINFO_attempts | USERINFO_blacklist; break; case 'L': lastlog_verb = 1; case 'l': show_info = USERINFO_lastlog; break; case 'h': display_users_help('s'); return 0; default: return 1; } } // Check if we have the needed search criteria if( crit_set == 0 ) { fprintf(stderr, "%s: Missing required parameter. You must provide either user id or user name\n", MODULE); xmlFreeDoc(srch_xml); return 1; } if( crit_set > 1 ) { fprintf(stderr, "%s: You cannot have several search criteria (-i | -u)\n", MODULE); xmlFreeDoc(srch_xml); return 1; } xmlStrPrintf(flags, 32, (xmlChar *) "%ld%c", show_info, 0); xmlNewChild(srch_root, NULL, (xmlChar *) "extractFlags", flags); // Do the query against the database if( (user_xml = eDBadminUserAccount(ctx, srch_xml)) == NULL ) { xmlFreeDoc(srch_xml); fprintf(stderr, "%s: User not found\n", MODULE); return 1; } xmlFreeDoc(srch_xml); if( eurephiaXML_IsResultMsg(ctx, user_xml) ) { eurephiaRESULT *res = eurephiaXML_ParseResultMsg(ctx, user_xml); if( res->resultType == exmlERROR ) { fprintf(stderr, "%s: %s\n", MODULE, res->message); free_nullsafe(ctx, res); xmlFreeDoc(user_xml); return 1; } free_nullsafe(ctx, res); } if( show_info & USERINFO_user ) { xsltparams[1] = "'userinfo'"; xslt_print_xmldoc(stdout, cfg, user_xml, "users.xsl", xsltparams); } // Show associated certificates if we was asked to show this info if( show_info & USERINFO_certs ) { xsltparams[1] = "''"; xslt_print_xmldoc(stdout, cfg, user_xml, "certificates.xsl", xsltparams); } // Show lastlog for the user, if requested if( show_info & USERINFO_lastlog ) { xmlNode *user_n = NULL; xsltparams[1] = "'list'"; if( lastlog_verb ) { xsltparams[1] = "'details'"; } user_n = eurephiaXML_getRoot(ctx, user_xml, "UserAccount", 1); user_n = xmlFindNode(user_n, "Account"); if( user_n == NULL ) { fprintf(stderr, "Could not retrieve valid data\n"); xmlFreeDoc(user_xml); return 1; } printf("** Lastlog entries for %s\n\n", xmlGetNodeContent(user_n, "username")); xslt_print_xmldoc(stdout, cfg, user_xml, "lastlog.xsl", xsltparams); } // Show login attempt info and/or blacklist info if( (show_info & USERINFO_attempts) || (show_info & USERINFO_blacklist) ) { xsltparams[1] = "'attemptblacklist'"; xslt_print_xmldoc(stdout, cfg, user_xml, "users.xsl", xsltparams); } // Clean up xmlFreeDoc(user_xml); return 0; } /** * This function handles activation, deactivation and deletion of an account * * @param ctx eurephiaCTX * @param sess eurephiaSESSION of the current logged in user * @param cfg eurephiaVALUES struct of the current configuration * @param argc argument count for the eurephiadm command * @param argv argument table for the eurephiadm command * * @return returns 0 on success, otherwise 1. */ int account_activation(eurephiaCTX *ctx, eurephiaSESSION *sess, eurephiaVALUES *cfg, int argc, char **argv) { xmlDoc *user_xml = NULL, *update_xml = NULL, *srch_xml = NULL, *tmp_xml = NULL, *res_xml = NULL; xmlNode *user_n = NULL, *update_n = NULL, *srch_root = NULL, *tmp_n = NULL, *fmap_n = NULL; eurephiaRESULT *res = NULL; char *uid_str = NULL, *activated = NULL, *deactivated = NULL, *actmode_str = NULL, *newpwd = NULL; int i, actmode = 0, rc = 0, crit_set = 0; xmlChar flags[34]; e_options activargs[] = { {"--uid", "-i", 1}, {"--username", "-u", 1}, {"--new-password", "-P", 1}, {"--help", "-h", 0}, {NULL, NULL, 0} }; assert((ctx != NULL) && (ctx->dbc != NULL) && (ctx->dbc->config != NULL)); if( (strcmp(argv[0], "--activate") == 0) || (strcmp(argv[0], "-a") == 0) ) { actmode = 'a'; actmode_str = "activated"; } else if( (strcmp(argv[0], "--deactivate") == 0) || (strcmp(argv[0], "-d") == 0) ) { actmode = 'd'; actmode_str = "deactivated"; } else if( (strcmp(argv[0], "--delete") == 0) || (strcmp(argv[0], "-D") == 0) ) { actmode = 'D'; actmode_str = "deleted"; } else if( (strcmp(argv[0], "--password") == 0) || (strcmp(argv[0], "-p") == 0) ) { actmode = 'p'; actmode_str = "updated with new password"; } else { fprintf(stderr, "%s: System error - illegal users mode'%s'\n", MODULE, argv[0]); return 1; } // Create a UserAccount query XML document eurephiaXML_CreateDoc(ctx, 1, "UserAccount", &srch_xml, &srch_root); xmlNewProp(srch_root, (xmlChar*) "mode", (xmlChar *) "view"); // Setup the fieldMapping - to narrow the search fmap_n = xmlNewChild(srch_root, NULL, (xmlChar *) "fieldMapping", NULL); xmlNewProp(fmap_n, (xmlChar *) "table", (xmlChar *)"users"); xmlStrPrintf(flags, 32, (xmlChar *) "%ld%c", USERINFO_user, 0); xmlNewChild(srch_root, NULL, (xmlChar *) "extractFlags", flags); // Argument parsing crit_set = 0; for( i = 1; i < argc; i++ ) { switch( eurephia_getopt(&i, argc, argv, activargs) ) { case 'i': if( atoi_nullsafe(optargs[0]) == 0 ) { fprintf(stderr, "%s: Invalid user id\n", MODULE); return 1; } xmlNewChild(fmap_n, NULL, (xmlChar *)"uid", (xmlChar *) optargs[0]); crit_set++; break; case 'u': if( strlen_nullsafe(optargs[0]) < 3 ) { fprintf(stderr, "%s: User name too short\n", MODULE); return 1; } xmlNewChild(fmap_n, NULL, (xmlChar *)"username", (xmlChar *)optargs[0]); crit_set++; break; case 'h': display_users_help(actmode); return 0; case 'P': newpwd = strdup_nullsafe(optargs[0]); break; default: return 1; } } // Check if we have the needed search criteria if( crit_set == 0 ) { fprintf(stderr, "%s: Missing required parameter. You must provide either user id or user name\n", MODULE); xmlFreeDoc(srch_xml); return 1; } if( crit_set > 1 ) { fprintf(stderr, "%s: You cannot have several search criteria (-i | -u)\n", MODULE); xmlFreeDoc(srch_xml); return 1; } // Do the query against the database if( (user_xml = eDBadminUserAccount(ctx, srch_xml)) == NULL ) { xmlFreeDoc(srch_xml); fprintf(stderr, "%s: User not found\n", MODULE); return 1; } xmlFreeDoc(srch_xml); if( eurephiaXML_IsResultMsg(ctx, user_xml) ) { eurephiaRESULT *res = eurephiaXML_ParseResultMsg(ctx, user_xml); if( res->resultType == exmlERROR ) { fprintf(stderr, "%s: %s\n", MODULE, res->message); free_nullsafe(ctx, res); xmlFreeDoc(user_xml); return 1; } free_nullsafe(ctx, res); } user_n = eurephiaXML_getRoot(ctx, user_xml, "UserAccount", 1); user_n = xmlFindNode(user_n, "Account"); if( user_n == NULL ) { xmlFreeDoc(user_xml); fprintf(stderr, "%s: No user account information found\n", MODULE); return 1; } uid_str = xmlGetAttrValue(user_n->properties, "uid"); activated = defaultValue(xmlGetNodeContent(user_n, "activated"), NULL); deactivated = defaultValue(xmlGetNodeContent(user_n, "deactivated"), NULL); // Create a new XML document which will be used to update the user account eurephiaXML_CreateDoc(ctx, 1, "UserAccount", &update_xml, &update_n); assert( (update_xml != NULL) && (update_n != NULL) ); xmlNewProp(update_n, (xmlChar *) "mode", (xmlChar *) "update"); xmlNewProp(update_n, (xmlChar *) "uid", (xmlChar *) uid_str); // Add fieldMapping - to correctly map eurephia fields into the database fields update_n = xmlNewChild(update_n, NULL, (xmlChar *) "fieldMapping", NULL); xmlNewProp(update_n, (xmlChar *) "table", (xmlChar *) "users"); switch( actmode ) { case 'a': // Activate a user account if( (activated != NULL) && (deactivated == NULL) ) { printf("%s: User account is already active\n", MODULE); goto exit; } else { // Set activated field to now() xmlNewChild(update_n, NULL, (xmlChar *) "activated", (xmlChar *) "CURRENT_TIMESTAMP"); // Remove deactivated flag tmp_n = xmlNewChild(update_n, NULL,(xmlChar *) "deactivated", NULL); xmlNewProp(tmp_n, (xmlChar *) "setnull", (xmlChar *) "1"); } // Do the update of the user account res_xml = eDBadminUserAccount(ctx, update_xml); break; case 'd': // Deactivate a user account if( (activated != NULL) && (deactivated != NULL) ) { printf("User account is already deactivated\n"); goto exit; } else if( (activated != NULL) ) { // Set deactivated to now() xmlNewChild(update_n, NULL, (xmlChar *) "deactivated", (xmlChar *) "CURRENT_TIMESTAMP"); } else { fprintf(stderr, "%s: User account is not activated yet\n", MODULE); goto exit; } // Do the update of the user account res_xml = eDBadminUserAccount(ctx, update_xml); break; case 'p': // Change password for a user // If we do not have a password .... ask for password via console if( newpwd == NULL ) { char *chkpwd = NULL; newpwd = (char *) malloc_nullsafe(ctx, 66); assert(newpwd != NULL); chkpwd = (char *) malloc_nullsafe(ctx, 66); assert(chkpwd != NULL); get_console_input(newpwd, 64, "Password for user:", 1); if( strlen_nullsafe(newpwd) < 4 ) { free_nullsafe(ctx, newpwd); free_nullsafe(ctx, chkpwd); fprintf(stderr, "%s: Password is too short\n", MODULE); goto exit; } get_console_input(chkpwd, 64, "Verify password for user:", 1); if( strcmp(newpwd, chkpwd) != 0 ) { free_nullsafe(ctx, newpwd); free_nullsafe(ctx, chkpwd); fprintf(stderr, "%s: Passwords didn't match\n", MODULE); goto exit; } free_nullsafe(ctx, chkpwd); } // Update with new password tmp_n = xmlNewChild(update_n, NULL, (xmlChar *) "password", (xmlChar *)newpwd); xmlNewProp(tmp_n, (xmlChar *) "pwhash", (xmlChar *) "none"); res_xml = eDBadminUserAccount(ctx, update_xml); free_nullsafe(ctx, newpwd); break; case 'D': // Delete user account xmlFreeDoc(update_xml); // We need another XML doc to delete users eurephiaXML_CreateDoc(ctx, 1, "UserAccount", &update_xml, &update_n); assert( (update_xml != NULL) && (update_n != NULL) ); xmlNewProp(update_n, (xmlChar *) "mode", (xmlChar *) "delete"); xmlNewProp(update_n, (xmlChar *) "uid", (xmlChar *) uid_str); update_n = xmlNewChild(update_n, NULL, (xmlChar *) "fieldMapping", NULL); xmlNewProp(update_n, (xmlChar *) "table", (xmlChar *) "users"); res_xml = eDBadminUserAccount(ctx, update_xml); // Check if this update failed and abort further operations if it did if( eurephiaXML_IsResultMsg(ctx, res_xml) ) { res = eurephiaXML_ParseResultMsg(ctx, res_xml); if( (res == NULL) || (res->resultType == exmlERROR) ) { free_nullsafe(ctx, res); break; } free_nullsafe(ctx, res); } else { // No ResultMsg document was returned, which is also wrong. break; } // Delete links between certificates associated to this user account xmlFreeDoc(update_xml); eurephiaXML_CreateDoc(ctx, 1, "usercerts", &update_xml, &update_n); assert( (update_xml != NULL) && (update_n != NULL) ); xmlNewProp(update_n, (xmlChar *) "mode", (xmlChar *) "remove"); update_n = xmlNewChild(update_n, NULL, (xmlChar *) "fieldMapping", NULL); xmlNewProp(update_n, (xmlChar *) "table", (xmlChar *) "usercerts"); xmlNewChild(update_n, NULL, (xmlChar *) "uid", (xmlChar *) uid_str); tmp_xml = eDBadminUserCertsLink(ctx, update_xml); res = eurephiaXML_ParseResultMsg(ctx, tmp_xml); if( res == NULL ) { fprintf(stderr, "%s: Failed to remove user <-> certificate link. " "No results received\n", MODULE); rc = 0; } else if( res->resultType == exmlERROR ) { fprintf(stderr, "%s: %s\n", MODULE, res->message); rc = 0; } else { fprintf(stdout, "%s: %s\n", MODULE, res->message); rc = 1; } // Remove all user access levels for the user. { xmlDoc *acclvl_d = NULL, *acclvl_res_xml = NULL; xmlNode *acclvl_n = NULL, *acclvl_fm = NULL; eurephiaRESULT *acclvl_res = NULL; eurephiaXML_CreateDoc(ctx, 1, "admin_access", &acclvl_d, &acclvl_n); xmlNewProp(acclvl_n, (xmlChar *) "mode", (xmlChar *) "revoke"); acclvl_fm = xmlNewChild(acclvl_n, NULL, (xmlChar *) "fieldMapping", NULL); xmlNewProp(acclvl_fm, (xmlChar *) "table", (xmlChar *) "eurephia_adminaccess"); xmlNewChild(acclvl_fm, NULL, (xmlChar *) "uid", (xmlChar *) uid_str); acclvl_res_xml = eDBadminAccessLevel(ctx, acclvl_d); acclvl_res = eurephiaXML_ParseResultMsg(ctx, acclvl_res_xml); if( acclvl_res->resultType == exmlERROR ) { fprintf(stderr, "%s: %s\n", MODULE, acclvl_res->message); rc = 0; } else { fprintf(stdout, "%s: %s\n", MODULE, acclvl_res->message); rc = rc ? 1 : 0; } free_nullsafe(ctx, res); free_nullsafe(ctx, acclvl_res); xmlFreeDoc(acclvl_res_xml); xmlFreeDoc(acclvl_d); } free_nullsafe(ctx, res); xmlFreeDoc(tmp_xml); break; } if( eurephiaXML_IsResultMsg(ctx, res_xml) ) { eurephiaRESULT *res = eurephiaXML_ParseResultMsg(ctx, res_xml); if( res->resultType == exmlERROR ) { fprintf(stderr, "%s: %s\n", MODULE, res->message); rc = 0; } else { fprintf(stdout, "%s: %s\n", MODULE, res->message); rc = rc ? 1 : 0; } free_nullsafe(ctx, res); } else { fprintf(stderr, "%s: Unknown error\n", MODULE); } xmlFreeDoc(res_xml); exit: xmlFreeDoc(user_xml); xmlFreeDoc(update_xml); return (rc != 1); } /** * users add mode. Creates a new user account. * * @param ctx eurephiaCTX * @param sess eurephiaSESSION of the current logged in user * @param cfg eurephiaVALUES struct of the current configuration * @param argc argument count for the eurephiadm command * @param argv argument table for the eurephiadm command * * @return returns 0 on success, otherwise 1. */ int add_user(eurephiaCTX *ctx, eurephiaSESSION *sess, eurephiaVALUES *cfg, int argc, char **argv) { xmlDoc *user_xml = NULL, *resxml = NULL; xmlNode *node = NULL, *node2 = NULL; eurephiaRESULT *res = NULL; struct stat cert_stat; int i = 0, certid = 0, uid = 0, certfile_format = CERTFILE_PEM; char *uname = NULL, *passwd = NULL, *certfile = NULL, *digest = NULL; e_options addu_args[] = { {"--username", "-u", 1}, {"--password", "-P", 1}, {"--certid", "-C", 1}, {"--certfile", "-c", 1}, {"--digest", "-D", 1}, {"--pkcs12", "-2", 0}, {"--help", "-h", 0}, {NULL, NULL, 0} }; assert((ctx != NULL) && (ctx->dbc != NULL) && (ctx->dbc->config != NULL)); // Parse arguments for( i = 1; i < argc; i++ ) { switch( eurephia_getopt(&i, argc, argv, addu_args) ) { case 'u': if( strlen_nullsafe(optargs[0]) < 3 ) { fprintf(stderr, "%s: username is too short\n", MODULE); return 1; } uname = optargs[0]; break; case 'P': if( strlen_nullsafe(optargs[0]) < 4 ) { fprintf(stderr, "%s: password is too short\n", MODULE); return 1; } passwd = strdup_nullsafe(optargs[0]); break; case 'C': if( (certid = atoi_nullsafe(optargs[0])) < 1 ) { fprintf(stderr, "%s: Invalid certid (numeric value > 0)\n", MODULE); return 1; } break; case 'c': // Check if certfile exists and is readable for us if( strlen_nullsafe(optargs[0]) < 1 ) { fprintf(stderr, "%s: certfile is too short\n", MODULE); return 1; } certfile = optargs[0]; if( stat(certfile, &cert_stat) == -1 ) { fprintf(stderr, "%s: Could not access certfile: %s (%s)\n", MODULE, certfile, strerror(errno)); return 1; } if( cert_stat.st_size == 0 ) { fprintf(stderr, "%s: certfile '%s' is empty\n", MODULE, certfile); return 1; } break; case '2': certfile_format = CERTFILE_PKCS12; break; case 'D': if( strlen_nullsafe(optargs[0]) < 59 ) { fprintf(stderr, "%s: Certificate digest is too short\n", MODULE); return 1; } digest = optargs[0]; break; case 'h': display_users_help('A'); return 0; default: return 1; } } // Make sure received arguments are sane if( uname == NULL ) { fprintf(stderr, "%s: Missing user name\n", MODULE); return 1; } if( ((certid > 0) && (digest != NULL)) || ((certid > 0) && (certfile != NULL)) || ((digest != NULL) && (certfile != NULL)) ) { fprintf(stderr, "%s: --certid, --certfile and --digest cannot be used together\n", MODULE); return 1; } // If we do not have a password .... ask for password via console if( passwd == NULL ) { char *chkpwd = NULL; passwd = (char *) malloc_nullsafe(ctx, 66); assert(passwd != NULL); chkpwd = (char *) malloc_nullsafe(ctx, 66); assert(chkpwd != NULL); get_console_input(passwd, 64, "Password for user:", 1); if( strlen_nullsafe(passwd) < 4 ) { free_nullsafe(ctx, passwd); free_nullsafe(ctx, chkpwd); fprintf(stderr, "%s: Password is too short\n", MODULE); return 1; } get_console_input(chkpwd, 64, "Verify password for user:", 1); if( strcmp(passwd, chkpwd) != 0 ) { free_nullsafe(ctx, passwd); free_nullsafe(ctx, chkpwd); fprintf(stderr, "%s: Passwords didn't match\n", MODULE); return 1; } free_nullsafe(ctx, chkpwd); } // Prepare add user XML document with fieldMapping eurephiaXML_CreateDoc(ctx, 1, "UserAccount", &user_xml, &node); xmlNewProp(node, (xmlChar *) "mode", (xmlChar *) "add"); node = xmlNewChild(node, NULL, (xmlChar *) "fieldMapping", NULL); xmlNewProp(node, (xmlChar *) "table", (xmlChar *) "users"); xmlNewChild(node, NULL, (xmlChar *) "username", (xmlChar *) uname); node2 = xmlNewChild(node, NULL, (xmlChar *) "password", (xmlChar *) passwd); xmlNewProp(node2, (xmlChar *) "pwhash", (xmlChar *) "none"); // Add the user resxml = eDBadminUserAccount(ctx, user_xml); xmlFreeDoc(user_xml); memset(passwd, 0, strlen_nullsafe(passwd)); free_nullsafe(ctx, passwd); if( (resxml == NULL) || !eurephiaXML_IsResultMsg(ctx, resxml) ) { fprintf(stderr, "%s: Failed to register the user. Unknown failure.\n", MODULE); return 1; } res = eurephiaXML_ParseResultMsg(ctx, resxml); if( res == NULL ) { fprintf(stderr, "%s: Failed to register the user. No results returned.\n", MODULE); xmlFreeDoc(resxml); return 1; } else if( res->resultType == exmlERROR ) { fprintf(stderr, "%s: %s\n", MODULE, res->message); xmlFreeDoc(resxml); free_nullsafe(ctx, res); return 1; } if( xmlStrcmp(res->details->children->name, (xmlChar *) "UserAccount") != 0 ) { fprintf(stderr, "%s: Invalid result value. User account might be registered\n", MODULE); xmlFreeDoc(resxml); free_nullsafe(ctx, res); return 1; } fprintf(stdout, "%s: %s\n", MODULE, res->message); uid = atoi_nullsafe(xmlGetAttrValue(res->details->properties, "uid")); xmlFreeDoc(resxml); free_nullsafe(ctx, res); if( (digest != NULL) || (certfile != NULL) ) { if( digest != NULL ) { xmlDoc *cert_xml = NULL, *certlist = NULL; xmlNode *cert_n = NULL; int certcount = 0; // when we have certificate digest, look that up eurephiaXML_CreateDoc(ctx, 1, "certificates", &cert_xml, &cert_n); assert( (cert_xml != NULL) && (cert_n != NULL) ); xmlNewProp(cert_n, (xmlChar *) "mode", (xmlChar *) "list"); xmlNewChild(cert_n, NULL, (xmlChar *) "sortkeys", (xmlChar *) "certid"); cert_n = xmlNewChild(cert_n, NULL, (xmlChar *) "fieldMapping", NULL); xmlNewProp(cert_n, (xmlChar *) "table", (xmlChar *) "certificates"); xmlNewChild(cert_n, NULL, (xmlChar *) "digest", (xmlChar *) digest); certlist = eDBadminCertificate(ctx, cert_xml); if( certlist == NULL ) { fprintf(stderr, "%s: Error while looking up certificate info.\n" "%s: User account is not associated with any certificates\n", MODULE, MODULE); xmlFreeDoc(cert_xml); goto exit; } xmlFreeDoc(cert_xml); cert_n = eurephiaXML_getRoot(ctx, certlist, "certificates", 1); if( cert_n == NULL ) { fprintf(stderr, "%s: Could not find certificates root node in XML document. " "No association done.\n", MODULE); xmlFreeDoc(certlist); goto exit; } certcount = atoi_nullsafe(xmlGetAttrValue(cert_n->properties, "certificates")); if( certcount == 0) { fprintf(stderr, "%s: No certificates was found. No association is done.\n", MODULE); xmlFreeDoc(certlist); goto exit; } else if( certcount > 1 ) { fprintf(stderr, "%s: More than one certificates was found. " "No association is done.\n", MODULE); xmlFreeDoc(certlist); goto exit; } // Get the first and only certificate node cert_n = xmlFindNode(cert_n, "certificate"); if( cert_n == NULL ) { fprintf(stderr, "%s: Could not find certificate node in XML document. " "No association done.\n", MODULE); xmlFreeDoc(certlist); goto exit; } // finally, we should have located the certid in the XML certid = atoi_nullsafe(xmlGetAttrValue(cert_n->properties, "certid")); xmlFreeDoc(certlist); } else if( certfile != NULL ) { // when we have certfile - register the certificate and register the link certinfo *ci = NULL; ci = Cert_ParseFile(certfile, certfile_format); if( ci == NULL ) { fprintf(stderr, "%s: Could not parse the certificate file. " "No association done.\n", MODULE); goto exit; } certid = register_certificate(ctx, 0, ci->digest, ci->common_name, ci->org, ci->email); if( certid == 0 ) { fprintf(stderr, "%s: Failed to register certificate file. No association done.", MODULE); } } } // If we have a certificate id, register a certificate link to the user account if( (certid > 0) && (uid > 0) ) { xmlDoc *usercert_xml = NULL, *res_xml = NULL; xmlNode *usercert_n = NULL; eurephiaRESULT *res = NULL; xmlChar tmp[66]; memset(&tmp, 0, 66); eurephiaXML_CreateDoc(ctx, 1, "usercerts", &usercert_xml, &usercert_n); assert( (usercert_xml != NULL) && (usercert_n != NULL) ); xmlNewProp(usercert_n, (xmlChar *) "mode", (xmlChar *) "register"); usercert_n = xmlNewChild(usercert_n, NULL, (xmlChar *) "fieldMapping", NULL); xmlNewProp(usercert_n, (xmlChar *) "table", (xmlChar *) "usercerts"); xmlStrPrintf(tmp, 64, (xmlChar *) "%i%c", uid, '\0'); xmlNewChild(usercert_n, NULL, (xmlChar *) "uid", tmp); xmlStrPrintf(tmp, 64, (xmlChar *) "%i%c", certid, '\0'); xmlNewChild(usercert_n, NULL, (xmlChar *) "certid", tmp); res_xml = eDBadminUserCertsLink(ctx, usercert_xml); if( res_xml == NULL ) { fprintf(stderr, "%s: Failed to register user <-> certificate link\n", MODULE); goto exit; } res = eurephiaXML_ParseResultMsg(ctx, res_xml); if( res == NULL ) { fprintf(stderr, "%s: Failed to register user <-> certificate link. " "No results received\n", MODULE); } else if( res->resultType == exmlERROR ) { fprintf(stderr, "%s: %s\n", MODULE, res->message); } free_nullsafe(ctx, res); xmlFreeDoc(res_xml); } exit: return (uid > 0); } /** * Main function for the users command. * * @param ctx eurephiaCTX * @param sess eurephiaSESSION of the current logged in user * @param cfg eurephiaVALUES struct of the current configuration * @param argc argument count for the eurephiadm command * @param argv argument table for the eurephiadm command * * @return returns 0 on success, otherwise 1. */ int cmd_Users(eurephiaCTX *ctx, eurephiaSESSION *sess, eurephiaVALUES *cfg, int argc, char **argv) { char **mode_argv; int i, mode_argc = 0, rc = 0; int (*mode_fnc) (eurephiaCTX *ctx, eurephiaSESSION *sess, eurephiaVALUES *cfg, int argc, char **argv); e_options modeargs[] = { {"--list", "-l", 0}, {"--show", "-s", 0}, {"--activate", "-a", 0}, {"--deactivate", "-d", 0}, {"--add", "-A", 0}, {"--delete", "-D", 0}, {"--password", "-p", 0}, {"--help", "-h", 0}, {NULL, NULL, 0} }; assert((ctx != NULL) && (ctx->dbc != NULL) && (ctx->dbc->config != NULL)); mode_fnc = NULL; for( i = 1; i < argc; i++ ) { switch( eurephia_getopt(&i, argc, argv, modeargs) ) { case 'l': mode_fnc = list_users; break; case 's': mode_fnc = show_user; break; case 'a': mode_fnc = account_activation; break; case 'd': mode_fnc = account_activation; break; case 'h': mode_fnc = help_Users2; break; case 'A': mode_fnc = add_user; break; case 'D': mode_fnc = account_activation; break; case 'p': mode_fnc = account_activation; break; default: break; } if( mode_fnc != NULL ) { break; } } // If we do not have any known mode defined, exit with error if( mode_fnc == NULL ) { fprintf(stderr, "Unknown argument. No mode given\n"); return 1; } // Allocate memory for our arguments being sent to the mode function mode_argv = (char **) calloc(sizeof(char *), (argc - i)+2); assert(mode_argv != NULL); // Copy over only the arguments needed for the mode mode_argc = eurephia_arraycp(i, argc, argv, mode_argv, (argc - i)); // Call the mode function rc = mode_fnc(ctx, sess, cfg, mode_argc, mode_argv); free_nullsafe(ctx, mode_argv); return rc; }