/* PureAdmin
* Copyright (C) 2003 Isak Savo
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
* Misc functions used to handle system accounts
*
* Copyright (C) 2006 Isak Savo
*/
#include <gtk/gtk.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <errno.h>
#include "globals.h"
#include "cfg.h"
#include "helper.h"
#include "system_accounts.h"
/*******************************************/
/* Private Functions */
/*******************************************/
typedef enum {
USERS,
GROUPS
} AccountType;
static gint cmp_system_accounts (SystemAccount *a, SystemAccount *b)
{
if (a->id < b->id)
return -1;
else if (a->id > b->id)
return 1;
return 0;
}
static GList *internal_get_system_ids(AccountType what)
{
FILE *fl;
GList *retval = NULL;
gchar buf[LINE_MAX], **arr;
gchar *filename;
if (what == USERS)
filename = "/etc/passwd";
else
filename = "/etc/group";
if ((fl = fopen (filename, "r")) == NULL)
{
pur_log_wrn ("Unable to open file %s: %s", filename, g_strerror(errno));
return NULL;
}
while (fgets (buf, LINE_MAX, fl))
{
arr = g_strsplit (buf, ":", -1);
if (arr_count (arr) < 2)
{
g_strfreev (arr);
continue;
}
SystemAccount *account = g_new0 (SystemAccount, 1);
if (arr[0][0] && arr[2][0] &&
atoi (arr[2]) > 0)
{
account->id = atoi(arr[2]);
account->name = g_strdup (arr[0]);
retval = g_list_insert_sorted (retval, account, (GCompareFunc) cmp_system_accounts);
}
g_strfreev (arr);
}
fclose (fl);
return g_list_first (retval);
}
static GList *internal_get_system_ids_str(AccountType what)
{
GList *list = internal_get_system_ids(what);
GList *node = list;
while (node)
{
SystemAccount *a = (SystemAccount*) node->data;
node->data = g_strdup_printf("%s (%d)", a->name, a->id);
system_account_free(a);
node = g_list_next(node);
}
return list;
}
static gboolean internal_get_account_id_exists(AccountType what, guint id)
{
GList *ids = internal_get_system_ids(what);
GList *node = ids;
gboolean found = FALSE;
while (node)
{
SystemAccount *a = (SystemAccount*) node->data;
if (a->id == id) {
found = TRUE;
/* We keep iterating the entire loop since we want to free all node data */
}
system_account_free(a);
node = g_list_next(node);
}
g_list_free(ids);
return found;
}
static guint internal_find_available_account_id(AccountType what, guint min_id)
{
GList *list = internal_get_system_ids(what);
GList *node = list;
guint last_id = 0, rv = 0;
while (node)
{
SystemAccount *a = (SystemAccount *) node->data;
node = g_list_next(node);
if (a->id <= min_id)
continue;
if (a->id > last_id + 1 && last_id > min_id)
{
rv = last_id + 1;
break;
}
last_id = a->id;
}
system_account_list_free(list);
if (rv == 0)
rv = last_id + 1;
return rv;
}
/*******************************************/
/* Public Functions */
/*******************************************/
GList *sys_get_user_ids (void)
{
return internal_get_system_ids(USERS);
}
GList *sys_get_group_ids (void)
{
return internal_get_system_ids(GROUPS);
}
GList *sys_get_user_ids_str (void)
{
return internal_get_system_ids_str(USERS);
}
GList *sys_get_group_ids_str (void)
{
return internal_get_system_ids_str(GROUPS);
}
gboolean sys_get_uid_exists(guint uid)
{
return internal_get_account_id_exists(USERS, uid);
}
gboolean sys_get_gid_exists(guint gid)
{
return internal_get_account_id_exists(GROUPS, gid);
}
guint sys_get_available_user_id (guint min_id)
{
return internal_find_available_account_id(USERS, min_id);
}
guint sys_get_available_group_id (guint min_id)
{
return internal_find_available_account_id(GROUPS, min_id);
}
gboolean sys_create_user (const gchar *username, guint userid, guint groupid, GError **err)
{
gint child_retval;
gboolean ret;
GError *spawn_err = NULL;
g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
if (!cfg.cmd_useradd) {
g_set_error (err, PUREADMIN_MAIN_ERROR,
PA_MAIN_ERROR_COMMAND_NOT_FOUND,
"Command 'useradd' isn't available");
return FALSE;
}
if (!MISC_VALID_STRING(username))
{
g_set_error(err, PUREADMIN_MAIN_ERROR,
PA_MAIN_ERROR_FAILED,
"Invalid username");
return FALSE;
}
gchar *cmd = g_strdup_printf ("%s -u %d -g %d -d /dev/null -c 'PureFTP User' -s /etc %s", cfg.cmd_useradd, userid, groupid, username);
pur_log_dbg ("Running command [%s]", cmd);
ret = g_spawn_command_line_sync (cmd, NULL, NULL, &child_retval, &spawn_err);
g_free (cmd);
child_retval = (signed char) WEXITSTATUS(child_retval);
if (child_retval){
g_set_error (err, PUREADMIN_MAIN_ERROR,
PA_MAIN_ERROR_FAILED,
"Child '%s' returned abnormally: %d", cfg.cmd_useradd, child_retval);
return FALSE;
}
if (!ret) {
g_set_error (err, PUREADMIN_MAIN_ERROR,
PA_MAIN_ERROR_FAILED,
"Couldn't spawn child process '%s': %s", cfg.cmd_useradd, spawn_err->message);
g_error_free(spawn_err);
return FALSE;
}
return TRUE;
}
/* Creates a new group with the specified name and id. If 'groupid' is 0, the groupadd command will pick one
* instead. */
gboolean sys_create_group (const gchar *groupname, guint groupid, GError **err)
{
gboolean ret;
gint child_retval;
GError *spawn_err = NULL;
g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
if (!cfg.cmd_groupadd) {
g_set_error (err, PUREADMIN_MAIN_ERROR,
PA_MAIN_ERROR_COMMAND_NOT_FOUND,
"Command 'groupadd' isn't available");
return FALSE;
}
if (!MISC_VALID_STRING(groupname))
{
g_set_error(err, PUREADMIN_MAIN_ERROR,
PA_MAIN_ERROR_FAILED,
"One or more arguments was incorrect");
return FALSE;
}
gchar *cmd;
if (groupid > 0)
cmd = g_strdup_printf ("%s -g %d %s", cfg.cmd_groupadd, groupid, groupname);
else
cmd = g_strdup_printf ("%s %s", cfg.cmd_groupadd, groupname);
pur_log_dbg ("Running command [%s]", cmd);
ret = g_spawn_command_line_sync (cmd, NULL, NULL, &child_retval, &spawn_err);
g_free (cmd);
child_retval = (signed char) WEXITSTATUS(child_retval);
if (child_retval){
g_set_error (err, PUREADMIN_MAIN_ERROR,
PA_MAIN_ERROR_FAILED,
"Child '%s' returned abnormally: %d", cfg.cmd_groupadd, child_retval);
return FALSE;
}
if (!ret) {
g_set_error (err, PUREADMIN_MAIN_ERROR,
PA_MAIN_ERROR_FAILED,
"Couldn't spawn child process '%s': %s", cfg.cmd_groupadd, spawn_err->message);
g_error_free(spawn_err);
return FALSE;
}
return TRUE;
}
/* Frees one SystemAccount object */
void system_account_free(SystemAccount *account)
{
if (account == NULL)
return;
g_free (account->name);
g_free (account);
}
/* Frees a GList containing SystemAccount objects */
void system_account_list_free (GList *list)
{
g_list_foreach(list, (GFunc) system_account_free, NULL);
g_list_free (list);
}
syntax highlighted by Code2HTML, v. 0.9.1