/* * GProFTPD - A GTK+ frontend for the ProFTPD standalone server. * Copyright (C) 2001 - 2006 Magnus Loef (Magnus-swe) * * 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. * */ #include "../config.h" #include #include #include #include #include "widgets.h" #include "gettext.h" #include "allocate.h" #include "commands.h" #include "show_info.h" #include "add_user.h" #include "functions.h" #include "dir_treeview_funcs.h" #include "system_defines.h" #include "populate_users.h" #include "populate_user_settings.h" #include "populate_conf_tab.h" #include "select_first_user.h" #include "reread_conf.h" #ifdef USE_DARWIN #include "osx_functions.h" #endif extern char global_server_address[1024]; extern char global_server_port[1024]; extern char global_server_type[1024]; extern int use_ratio; extern int use_quota; extern long num_rows; extern int row_pos; /* Used globally with dir_treeview_funcs.c */ char *user_profile; /* Set in dir_treeview_funcs.c */ extern gchar *homedir; /* Declared in gproftpd.c and set in treeview_dir_funcs */ extern int global_dir_error; /* Temporary, for option deprecations in proftpd */ extern char global_version[1024]; void add_user(struct w *widgets) { /* Adds a new user to the selected server */ FILE *fp; long conf_size = 0; long profile_size = 0; char *old_buffer, *new_buffer; char *user_check, *address_buffer, *port_buffer; int length=0, limit_access=0, user_added=0; int found_server=0, standard_server=0; gchar *utf8=NULL; gchar *info, *cmd, *restricted_dir=NULL; G_CONST_RETURN gchar *br=NULL, *brc=NULL, *fr=NULL, *frc=NULL; G_CONST_RETURN gchar *username; G_CONST_RETURN gchar *password; G_CONST_RETURN gchar *group; G_CONST_RETURN gchar *comment; G_CONST_RETURN gchar *shell; username = gtk_entry_get_text(GTK_ENTRY(widgets->user_set_entry[0])); password = gtk_entry_get_text(GTK_ENTRY(widgets->user_set_entry[1])); group = gtk_entry_get_text(GTK_ENTRY(widgets->user_set_entry[2])); comment = gtk_entry_get_text(GTK_ENTRY(widgets->user_set_entry[3])); /* Shell is a gtk_combo_box_entry_new_text */ shell = gtk_entry_get_text(GTK_ENTRY(GTK_BIN(widgets->user_set_combo[0])->child)); /* If the shell is false it will add the users directory as /dev/null and the specified false shell. * If the shell is real it will add the users directory as /USERSHOME/username and the specified real shell. * The ftp directory will be located where specified in the application. * This is done so that no user gets sshd/etc access unless the admin wants to. */ /* Ratios */ if( use_ratio ) { br = gtk_entry_get_text(GTK_ENTRY(widgets->user_set_spinbutton[1])); brc = gtk_entry_get_text(GTK_ENTRY(widgets->user_set_spinbutton[2])); fr = gtk_entry_get_text(GTK_ENTRY(widgets->user_set_spinbutton[3])); frc = gtk_entry_get_text(GTK_ENTRY(widgets->user_set_spinbutton[4])); } /* If the username field is empty inform that this cant be done. */ length = strlen(username); if( length == 0 ) { info = g_strdup_printf(_("You must specify a username.\n")); show_info(info); g_free(info); return; } if( username[0]=='0'||username[0]=='1'||username[0]=='2'||username[0]=='3'||username[0]=='4' || username[0]=='5'||username[0]=='6'||username[0]=='7'||username[0]=='8'||username[0]=='9') { info = g_strdup_printf(_("Failed adding user: %s\nA user name can not begin with a number.\n"), username); show_info(info); g_free(info); return; } if( username[0]=='r' && username[1]=='o' && username[2]=='o' && username[3]=='t' && strlen(username) == 4 ) { info = g_strdup_printf(_("Failed adding user: %s\nThe user root can not be added for security reasons.\n"), username); show_info(info); g_free(info); return; } if( strstr((char *)username, "<") || strstr((char *)username, ">") ) { info = g_strdup_printf(_("Failed adding user: %s\nchars \"<\" and \">\" arent allowed.\n"), username); show_info(info); g_free(info); return; } /* If the password field has less then 6 chars we inform that this cant be done */ length = strlen(password); if( length < 6 ) { info = g_strdup_printf(_("Failed adding user: %s\nA minimum password length of 6 chars is required.\n"), username); show_info(info); g_free(info); return; } /* If the group filed has less then 3 chars we inform that this cant be done */ length = strlen(group); if( length == 0 ) { info = g_strdup_printf(_("Failed adding user: %s\nNo group specified.\n"), username); show_info(info); g_free(info); return; } /* If the shell field has less then 3 chars we inform that this cant be done */ length = strlen(shell); if( length < 3 ) { info = g_strdup_printf(_("Failed adding user: %s\nNo shell specified.\n"), username); show_info(info); g_free(info); return; } /* A comment is required */ length = strlen(comment); if( length == 0 ) { info = g_strdup_printf(_("A comment is required to add a user.\n")); show_info(info); g_free(info); return; } /* Check if the user exists in the selected server */ if((fp=fopen(PROFTPD_CONF,"r"))==NULL) { info = g_strdup_printf(_("Failed adding user: %s\nCant open proftpd.conf.\n"), username); show_info(info); g_free(info); return; } fseek(fp, 0, SEEK_END); conf_size = ftell(fp); rewind(fp); old_buffer = allocate(conf_size); user_check = allocate(4096); snprintf(user_check, 4000, "User %s\n", username); address_buffer = allocate(8192+15); port_buffer = allocate(8192+3); if( strstr((char *)global_server_type, "Virtualhost") ) sprintf(address_buffer, "\n", global_server_address); else standard_server = 1; sprintf(port_buffer, "Port %s\n", global_server_port); /* Scroll to the correct vhost */ if( ! standard_server && conf_size > 1 ) while(fgets(old_buffer, conf_size, fp)!=NULL) { /* The correct server address is found */ if( ! found_server && ! strcmp(old_buffer, address_buffer) ) { /* Lets see if its the same port as the selected one */ while(fgets(old_buffer, conf_size, fp)!=NULL) { if( strstr(old_buffer, "Port") && ! strcmp(old_buffer, port_buffer) ) { found_server = 1; break; } /* End of vhost, break and check the next vhost */ if( strstr(old_buffer, "") ) break; } } /* This vhost has the correct address and port */ if( found_server ) break; } /* The selected vhost was not found */ if( ! standard_server && ! found_server ) { info = g_strdup_printf(_("Failed adding user: %s\nThe selected virtual host was not found.\n"), username); show_info(info); g_free(info); free(old_buffer); free(user_check); free(address_buffer); free(port_buffer); fclose(fp); return; } /* We have begun at the top for the standard server * or scrolled to the selected vhost. */ /* Check if the user exists in this selected vhost or standard server */ if( conf_size > 1 ) while(fgets(old_buffer, conf_size, fp)!=NULL) { if( ! strcmp(old_buffer, user_check) && ! strstr(old_buffer, "AllowUser") && ! strstr(old_buffer, "FakeUser") ) { info = g_strdup_printf(_("Failed adding user: %s\nThe user already exists in this server.\n"), username); show_info(info); g_free(info); free(old_buffer); free(user_check); free(address_buffer); free(port_buffer); fclose(fp); return; } /* End the search if we are looking for a standard user and the end of the standard server is found */ if( standard_server && strstr(old_buffer, "directory_store), (GtkTreeModelForeachFunc) num_rows_func, widgets); if( num_rows < 1 ) { info = g_strdup_printf(_("Missing ftp home directory. Scroll down and add one first.\n")); show_info(info); g_free(info); return; } /* (Global) Statics + entries + (number of rows * dirlen + APPE STOR STOU etc) */ profile_size = 16384 + 1400 + (num_rows * 16384); /* Allocate the user profile */ user_profile = allocate(profile_size+1); /* Set the users home dir and its access settings globally */ row_pos = 0; /* Only get the home directory */ gtk_tree_model_foreach(GTK_TREE_MODEL(widgets->directory_store), (GtkTreeModelForeachFunc) dirs_foreach, widgets); /* Bad directory name or no directory at all */ if( global_dir_error ) { /* Info is shown in the foreach function */ global_dir_error = 0; free(user_profile); if( homedir!=NULL ) g_free(homedir); return; } /* If ratios is used it needs a restricted toplevel directory and a block all .ftpaccess file in this toplevel directory */ if( use_ratio ) { /* Make the restricted directory under each users chroot directory */ restricted_dir = g_strdup_printf("%s/%s", homedir, "restricted"); make_dir_chmod((gchar *)restricted_dir, "0777"); /* Must be like this */ /* Add a block all .ftpaccess file to this directory */ cmd = g_strdup_printf("echo \"DenyAll\n\" > %s/.ftpaccess", restricted_dir); if( ! run_command(cmd) ) { printf("Error creating .ftpaccess file here: %s/.ftpaccess\n", restricted_dir); /* Fixme, popup */ } g_free(cmd); /* Add the ratio files */ cmd = g_strdup_printf("touch %s/proftpd_ratios %s/proftpd_ratios_temp", restricted_dir, restricted_dir); if( ! run_command(cmd) ) { printf("Error creating the ratio files here: %s\n", restricted_dir); /* Fixme, popup */ } g_free(cmd); /* Chmod a+rw on the ratio files (must be a+rw) */ cmd = g_strdup_printf("chmod a+rw %s/proftpd_ratios %s/proftpd_ratios_temp", restricted_dir, restricted_dir); if( ! run_command(cmd) ) { printf("Error chmodding the ratio files here: %s\n", restricted_dir); /* Fixme, popup */ } g_free(cmd); /* Chown ratio files to SERVERUSER:SERVERGROUP */ cmd = g_strdup_printf("chown %s:%s %s/proftpd_ratios %s/proftpd_ratios_temp", SERVER_USER, SERVER_GROUP, restricted_dir, restricted_dir); if( ! run_command(cmd) ) { printf("Error chmodding the ratio files here: %s\n", restricted_dir); /* Fixme, popup */ } g_free(cmd); g_free(restricted_dir); } /* The users configuration profile */ strcpy(user_profile, "\n\n"); strcat(user_profile, "User "); strcat(user_profile, username); strcat(user_profile, "\nGroup "); strcat(user_profile, group); strcat(user_profile, "\n"); strcat(user_profile, "AnonRequirePassword on\n"); strcat(user_profile, "MaxClients 5 \"The server is full, hosting %m users\"\n"); strcat(user_profile, "DisplayLogin welcome.msg\n"); /* Fix for a changed directive, sorry Fedora backported... */ // if( strstr(global_version, "1.2.") || strstr(global_version, "1.3.0") ) // strcat(user_profile, "DisplayFirstChdir .msg\n"); // else // strcat(user_profile, "DisplayChdir .msg\n"); /* Ratio Module (reversed br/fr order in the gui) */ if( use_ratio ) { strcat(user_profile, "UserRatio "); strcat(user_profile, username); strcat(user_profile, " "); strcat(user_profile, fr); strcat(user_profile, " "); strcat(user_profile, frc); strcat(user_profile, " "); strcat(user_profile, br); strcat(user_profile, " "); strcat(user_profile, brc); strcat(user_profile, "\n"); } strcat(user_profile, "\n"); strcat(user_profile, " Allow from all\n"); strcat(user_profile, " Deny from all\n"); strcat(user_profile, "\n"); strcat(user_profile, "AllowOverwrite off\n"); append_limit_cmds(); row_pos = 1; /* Append and create the rest of the directories */ gtk_tree_model_foreach(GTK_TREE_MODEL(widgets->directory_store), (GtkTreeModelForeachFunc) dirs_foreach, widgets); strcat(user_profile, "\n"); if( homedir!=NULL ) g_free(homedir); /* Add the new user settings and AllowUser to the correct server */ found_server = 0; /* Standard server selected, start adding users directly */ if( standard_server ) found_server = 1; /* Add AllowUser UserName to the selected server */ if((fp=fopen(PROFTPD_CONF,"r"))==NULL) { free(address_buffer); free(port_buffer); free(user_profile); return; } fseek(fp, 0, SEEK_END); conf_size = ftell(fp); rewind(fp); old_buffer = allocate(conf_size); new_buffer = allocate(conf_size+8192); if( conf_size > 1 ) while(fgets(old_buffer, conf_size, fp)!=NULL) { strcat(new_buffer, old_buffer); if( ! standard_server && ! found_server && ! strcmp(old_buffer, address_buffer) ) { /* Lets see if this is the selected server */ while(fgets(old_buffer, conf_size, fp)!=NULL) { strcat(new_buffer, old_buffer); /* This will expect the servers port on the second line ! * else itll miss some vaules .. */ if( strstr(old_buffer, "Port") && ! strcmp(old_buffer, port_buffer) ) { found_server = 1; break; } if( strstr(old_buffer, "") ) break; } } /* Continue until we find the selected server */ if( ! found_server ) continue; /* Add AllowUser Username .. to this server only */ if( strstr(old_buffer, " */ while(fgets(old_buffer, conf_size, fp)!=NULL) { strcat(new_buffer, old_buffer); if( strstr(old_buffer, "