diff options
author | Jan Lipovsky <janlipovsky@gmail.com> | 2010-05-28 13:59:28 +0200 |
---|---|---|
committer | Jan Lipovsky <janlipovsky@gmail.com> | 2010-05-28 13:59:28 +0200 |
commit | ba2bbc75e63b968d03da1094fcb8f28a1f734b39 (patch) | |
tree | b2c56735780032dab543167bafd3139f7f73903e /sfshare-daemon/samba_share.c | |
parent | b282327da5b515ce3288b1084bf1e21cf01c49af (diff) | |
download | sfshare-master.tar.gz sfshare-master.tar.xz sfshare-master.zip |
Diffstat (limited to 'sfshare-daemon/samba_share.c')
-rwxr-xr-x | sfshare-daemon/samba_share.c | 955 |
1 files changed, 955 insertions, 0 deletions
diff --git a/sfshare-daemon/samba_share.c b/sfshare-daemon/samba_share.c new file mode 100755 index 0000000..a58042b --- /dev/null +++ b/sfshare-daemon/samba_share.c @@ -0,0 +1,955 @@ +/* + * samba_share.c + * + * 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 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Author: Jan Lipovsky <janlipovsky@gmail.com> + */ + +#include <string.h> /* strlen, strstr */ +#include <stdlib.h> /* system() call */ + +#include <glib.h> +#include <glib/gstdio.h> + +#include "samba_share.h" +#include "sfshare_errors.h" + +/* Define */ +#define SECTIONS_COUNT 3 /* Count of special sections in smb.conf */ +#define KEYWORDS_COUNT 6 /* Count of keywords used for setup share in smb.conf */ + + +/* [share name], "path =", "commennt =", "read only =", "writable =, writeable =, write ok =", "guest ok =" */ +const gchar *keywords[KEYWORDS_COUNT] = {"[" ,"path", "comment", "read only", "writ", "guest"}; + +typedef enum keywords_id +{ + SHARE_NAME_ID = 0, + PATH_ID, + COMMENT_ID, + READ_ONLY_ID, + WRTITABLE_ID, + GUEST_OK_ID +} TKeywords_id; + +/* Path too smb.conf */ +gchar *smb_conf_path = "/etc/samba/smb.conf"; +const gchar *smb_special_section [SECTIONS_COUNT] = {"global", "homes", "printers"}; + + +/** Send SIGHUP to smb and nmb */ +void +smb_reload_service () +{ + system("killall -HUP smb nmb"); +} + +/** +* Function changes path to smb.conf to path +*/ +void +set_smbconf_path (const gchar *path) +{ + smb_conf_path = g_strdup(path); +} + + +/** +* Save string str as new smb.conf +*/ +gint +write_smbconf (const gchar *content) +{ + FILE *smb_file; + + /* smb.conf - File exist test */ + if(!g_file_test (smb_conf_path, G_FILE_TEST_EXISTS)) + { + g_warning ("Config file \"%s\" does not exist!", smb_conf_path); + return ERROR_FILE_NOT_EXIST; + } + + /* Try open smb.conf - rewrite all */ + smb_file = fopen(smb_conf_path, "w"); + if(smb_file == NULL) + { + g_warning ("Can not open file \"%s\"! Maybe, you dont have rights for change smb.conf", smb_conf_path); + return ERROR_CAN_NOT_OPEN_FILE; + } + + /* Write to smb.conf */ + if(fputs (content,smb_file) == EOF) + { + g_warning ("Can not write to file \"%s\"!", smb_conf_path); + return ERROR_CAN_NOT_WRITE_TO_FILE; + } + + fclose(smb_file); + + return OK; +} + + +/** +* Function free TSmbConfItem from memmory +*/ +void +smbconf_item_free(TSmbConfItem *item) +{ + g_string_free(item->guest_ok, TRUE); + g_string_free(item->writable, TRUE); + g_string_free(item->read_only, TRUE); + g_string_free(item->comment, TRUE); + g_string_free(item->path, TRUE); + g_string_free(item->name, TRUE); + + g_free(item); +} + + +/** +* Function allocs memory for TSmbConfItem +*/ +TSmbConfItem* +smbconf_item_new0 () +{ + TSmbConfItem *ret; + ret = g_malloc(sizeof(struct smb_conf_item)); + + ret->name = g_string_new(""); + ret->path = g_string_new(""); + ret->comment = g_string_new(""); + ret->read_only = g_string_new(""); + ret->writable = g_string_new(""); + ret->guest_ok = g_string_new(""); + + return ret; +} + + +/** +* Function allocs memory for TSmbConfItem +*/ +TSmbConfItem* +smbconf_item_new (const gchar *name, const gchar *path, const gchar *comment, const gchar *read_only, const gchar *guest_ok) +{ + TSmbConfItem *ret; + ret = g_malloc(sizeof(struct smb_conf_item)); + + ret->name = g_string_new(name); + ret->path = g_string_new(path); + ret->comment = g_string_new(comment); + + ret->read_only = g_string_new(read_only); + + if (!g_strcmp0(read_only,"yes")) + ret->writable = g_string_new("no"); + else + ret->writable = g_string_new("yes"); + + ret->guest_ok = g_string_new(guest_ok); + + return ret; +} + +/** +* Function returns new array +*/ +GPtrArray* +shared_items_array_new () +{ + GPtrArray *ret = g_ptr_array_new(); + return ret; +} + + +/** +* Destroy array +*/ +void +shared_items_array_free (GPtrArray *array) +{ + TSmbConfItem *tmp; + gint i; + for(i = 0; i < array->len; i++) + { + tmp = g_ptr_array_index (array,i); + smbconf_item_free (tmp); + } + + g_ptr_array_free(array, TRUE); +} + + +/** +* If ok return 0 else return number of error +*/ +gint check_item(TSmbConfItem *item) +{ + if(item->name->len <= 0) + return ERROR_WRONG_NAME; + + if(item->path->len <= 0) + return ERROR_WRONG_PATH; + + /* read_only = true ... writable muust be = false */ + if(g_string_equal(item->writable, item->read_only) && item->writable->len > 0) + return ERROR_READONLY_WRITABLE; + + return OK; +} + + +/** +* Parse line of smb.conf and fill competent field of item structure +*/ +void +parse_to_share_item (gchar *txt, TSmbConfItem *item) +{ + gchar *lower = g_ascii_strdown(txt, strlen(txt)); + gboolean found = FALSE; + + /* Find keywords on line *txt */ + gint i; + for(i = 0; i < KEYWORDS_COUNT; i++) + { + gchar *point; + if((point = strstr(lower,keywords[i])) != NULL) + { + /* Keywords must be at begining of line */ + if(point == lower) + { + found = TRUE; + break; + } + } + } + + /* Save atributes - Boolean variables case-insensitive - yes, no, true, false, 1, or 0 */ + if(found) + switch(i) + { + /* [share name] */ + case SHARE_NAME_ID: + { + g_string_append_len(item->name, txt + 1, strlen(txt)-2); + } + break; + + /* path = */ + case PATH_ID: + { + gchar *tmp; + if((tmp = strstr(txt,"=")) != NULL) + { + g_string_assign(item->path, g_strstrip(tmp + 1)); + } + } + break; + + /* comment = */ + case COMMENT_ID: + { + gchar *tmp; + if((tmp = strstr(txt,"=")) != NULL) + { + g_string_assign(item->comment, g_strstrip(tmp + 1)); + } + } + break; + + /* read only = */ + case READ_ONLY_ID: + { + gchar *tmp; + if((tmp = strstr(lower,"=")) != NULL) + { + g_strstrip(++tmp); + + if(g_strcmp0(tmp, "yes") && g_strcmp0(tmp, "true") && g_strcmp0(tmp, "1")) + g_string_assign(item->read_only,"no"); + else + g_string_assign(item->read_only,"yes"); + } + } + break; + + /* writ = writable, writeable, write ok = */ + case WRTITABLE_ID: + { + gchar *tmp; + if((tmp = strstr(lower,"=")) != NULL) + { + g_strstrip(++tmp); + + if(g_strcmp0(tmp, "yes") && g_strcmp0(tmp, "true") && g_strcmp0(tmp, "1")) + g_string_assign(item->writable,"no"); + else + g_string_assign(item->writable,"yes"); + } + } + break; + + /* guest ok = */ + case GUEST_OK_ID: + { + gchar *tmp; + if((tmp = strstr(lower,"=")) != NULL) + { + g_strstrip(++tmp); + + if(g_strcmp0(tmp, "yes") && g_strcmp0(tmp, "true") && g_strcmp0(tmp, "1")) + g_string_assign(item->guest_ok,"no"); + else + g_string_assign(item->guest_ok,"yes"); + } + } + break; + + default: + break; + } + + g_free(lower); +} + + + +/** +* Funciton loads all share section to array +*/ +gint +load_smb_conf (GPtrArray *shared_items) +{ + + FILE *smb_file; /* Samba config file */ + gchar *line; /* Line buffer */ + gboolean skip = FALSE; /* Skip lines of special sections */ + + gint arr_index = shared_items->len - 1; /* Count of items in shared_items array - 1; */ + + /* smb.conf - File exist test */ + if (!g_file_test(smb_conf_path, G_FILE_TEST_EXISTS)) + { + g_warning ("Config file \"%s\" not exist!", smb_conf_path); + return ERROR_FILE_NOT_EXIST; + } + + /* Try open smb.conf */ + smb_file = fopen(smb_conf_path, "r"); + if (smb_file == NULL) + { + g_warning ("Can not open file \"%s\"!", smb_conf_path); + return ERROR_CAN_NOT_OPEN_FILE; + } + + /* Inicialize buffers */ + line = g_strnfill(BUFSIZ, '\0'); + + /* Parse smb.conf file and load shared folders setings */ + while (fgets(line, BUFSIZ, smb_file)) + { + /* Remove white space */ + g_strstrip(line); + + /* Skip comments and empty lines */ + if(line[0] == ';' || line[0] == '#' || line[0] == '\0') + continue; + + if(line[0] == '[') + { + skip = FALSE; + + /* Test special sections */ + gint i ; + for (i = 0; i < SECTIONS_COUNT; i++) + { + if(strstr(line,smb_special_section[i]) != NULL) + { + skip = TRUE; + break; + } + } + + if(!skip) + { + /* Start of share section - alloc new item of array */ + TSmbConfItem *tmp_item = smbconf_item_new0(); + + /* Add item to array */ + g_ptr_array_add(shared_items, (gpointer) tmp_item); + arr_index++; + + /* Print error if pointers are different */ + if (g_ptr_array_index (shared_items, arr_index) != (gpointer) tmp_item) + g_warning ("load_smb_conf (GPtrArray **shared_items): got %p instead of %p\n", + g_ptr_array_index(shared_items, arr_index), tmp_item); + } + } + + /* Skip special sections (global, homes, printers) */ + if(skip) + continue; + + TSmbConfItem *tmp = g_ptr_array_index(shared_items, arr_index); + + /* Recognize parameters and fill in item */ + parse_to_share_item (line, tmp); + + } + + /* Free */ + g_free(line); + + fclose(smb_file); + + return 0; +} + + +/** +* Returns share imte if directory [path] is shared, +* if not return NULL; +*/ +TSmbConfItem +*is_shared_item(GPtrArray *shared_items, const gchar *path) +{ + TSmbConfItem *ret = NULL; + + TSmbConfItem *tmp; + gint i; + for(i = 0; i < shared_items->len; i++) + { + tmp = g_ptr_array_index(shared_items,i); + if(strstr(tmp->path->str,path)) + { + ret = tmp; + break; + } + } + + return ret; +} + + +/** +* True if share name exist +*/ +gboolean +share_name_exist (GPtrArray *shared_items, const gchar *sharename) +{ + TSmbConfItem *tmp; + gint i; + for(i = 0; i < shared_items->len; i++) + { + tmp = g_ptr_array_index(shared_items,i); + if(strstr(tmp->name->str,sharename)) + { + return TRUE; + } + } + + return FALSE; +} + + +/** +* Write new share section or change chare section defined by share parameter +*/ +gint +write_share (GPtrArray *shared_items, TSmbConfItem *share) +{ + + TSmbConfItem *item; /* Shared item */ + FILE *smb_file; /* Samba config file */ + GString *smb_conf_new; /* Content of smb.conf */ + gchar *line; /* Line buffer */ + gchar *tmp; /* Temp */ + + gboolean writed_change [KEYWORDS_COUNT] = {FALSE}; + gboolean check_writed_changes = FALSE; + gboolean new_share = FALSE; + gboolean change = FALSE; + gboolean found = FALSE; + + item = is_shared_item(shared_items, share->path->str); + + /* If item is not shared we just append it to end of smb.conf */ + if(!item) + { + if(share_name_exist(shared_items, share->name->str)) + return ERROR_SHARE_NAME_EXIST; + + new_share = TRUE; + } + + /* smb.conf - File exist test */ + if(!g_file_test(smb_conf_path, G_FILE_TEST_EXISTS)) + { + g_warning ("Config file \"%s\" does not exist!", smb_conf_path); + return ERROR_FILE_NOT_EXIST; + } + + /* Try open smb.conf - rewrite all */ + smb_file = fopen(smb_conf_path, "r"); + if(smb_file == NULL) + { + g_warning ("Can not open file \"%s\"!", smb_conf_path); + return ERROR_CAN_NOT_OPEN_FILE; + } + + /* Inicialize buffers */ + smb_conf_new = g_string_new(""); + line = g_strnfill(BUFSIZ, '\0'); + tmp = g_strnfill(BUFSIZ, '\0'); + + + /* Load smb.conf, change or add share section share */ + while(fgets(line, BUFSIZ, smb_file)) + { + gchar *orig = g_strdup(line); + + /* Remove white space */ + g_strstrip(line); + + if(!new_share) /* Find section to change */ + if(line[0] == '[') + { + if (change) /* Section to change ends, check if all atributes are wroted */ + check_writed_changes = TRUE; + + change = FALSE; + + /* Is this section to change? */ + if(strstr(line,item->name->str)) + { + change = TRUE; + } + } + + if(check_writed_changes) + { + /* Section name and path are allways writed */ + + if(!writed_change[COMMENT_ID] && (share->comment->len > 0)) + { + g_string_append_printf(smb_conf_new, "\tcomment = %s\n",share->comment->str); + } + + if(!writed_change[READ_ONLY_ID] && (share->read_only->len > 0)) + { + g_string_append_printf(smb_conf_new, "\tread only = %s\n",share->read_only->str); + } + + if(!writed_change[WRTITABLE_ID] && (share->writable->len > 0)) + { + g_string_append_printf(smb_conf_new, "\twritable = %s\n",share->writable->str); + } + + if(!writed_change[GUEST_OK_ID] && (share->guest_ok->len > 0)) + { + g_string_append_printf(smb_conf_new, "\tguest ok = %s\n",share->guest_ok->str); + } + } + + + /* New share or no change */ + if(!change || new_share) + { + /* Just copy text from smb.conf */ + g_string_append(smb_conf_new,orig); + } + else + { + /* Change this line */ + gchar *lower = g_ascii_strdown(line, strlen(line)); /* lower line */ + + found = FALSE; + + /* Find keywords on line *txt */ + gint i; + for(i = 0; i < KEYWORDS_COUNT; i++) + { + gchar *point; + if((point = strstr(lower,keywords[i])) != NULL) + { + /* Keywords must be at begining of line */ + if(point == lower) + { + found = TRUE; + break; + } + } + } + + /* Change share atributes */ + if(found) + switch(i) + { + /* [share name] */ + case SHARE_NAME_ID: + { + g_string_append_printf(smb_conf_new, "[%s]\n",share->name->str); + writed_change[SHARE_NAME_ID] = TRUE; + } + break; + + + /* path = */ + case PATH_ID: + { + /* no change - path must be same */ + g_string_append(smb_conf_new,orig); + writed_change[PATH_ID] = TRUE; + } + break; + + + /* comment = */ + case COMMENT_ID: + { + if(share->comment->len > 0) + { + + g_string_append_printf(smb_conf_new, "\tcomment = %s\n",share->comment->str); + writed_change[COMMENT_ID] = TRUE; + } + } + break; + + + /* read only = */ + case READ_ONLY_ID: + { + + if(share->read_only->len > 0) + { + g_string_append_printf(smb_conf_new, "\tread only = %s\n",share->read_only->str); + writed_change[READ_ONLY_ID] = TRUE; + } + } + break; + + + /* writ = writable, writeable, write ok = */ + case WRTITABLE_ID: + { + if(share->writable->len > 0) + { + g_string_append_printf(smb_conf_new, "\twritable = %s\n",share->writable->str); + writed_change[WRTITABLE_ID] = TRUE; + } + } + break; + + + /* guest ok = */ + case GUEST_OK_ID: + { + if(share->guest_ok->len > 0) + { + g_string_append_printf(smb_conf_new, "\tguest ok = %s\n",share->guest_ok->str); + writed_change[GUEST_OK_ID] = TRUE; + } + } + break; + + default: + break; + } + + g_free(lower); + } + + g_free(orig); + } + + if(!check_writed_changes && change) + { + /* Section name and path are allways writed */ + + if(!writed_change[COMMENT_ID] && (share->comment->len > 0)) + { + g_string_append_printf(smb_conf_new, "\tcomment = %s\n",share->comment->str); + } + + if(!writed_change[READ_ONLY_ID] && (share->read_only->len > 0)) + { + g_string_append_printf(smb_conf_new, "\tread only = %s\n",share->read_only->str); + } + + if(!writed_change[WRTITABLE_ID] && (share->writable->len > 0)) + { + g_string_append_printf(smb_conf_new, "\twritable = %s\n",share->writable->str); + } + + if(!writed_change[GUEST_OK_ID] && (share->guest_ok->len > 0)) + { + g_string_append_printf(smb_conf_new, "\tguest ok = %s\n",share->guest_ok->str); + } + } + + + /* Create new share */ + if(new_share) + { + + g_string_append_printf(smb_conf_new, "\n[%s]\n",share->name->str); + + g_string_append_printf(smb_conf_new, "\tpath = %s\n",share->path->str); + + + if(share->comment->len > 0) + { + g_string_append_printf(smb_conf_new, "\tcomment = %s\n",share->comment->str); + } + + + if(share->read_only->len > 0) + { + g_string_append_printf(smb_conf_new, "\tread only = %s\n",share->read_only->str); + } + + if(share->writable->len > 0) + { + g_string_append_printf(smb_conf_new, "\twritable = %s\n",share->writable->str); + } + + if(share->guest_ok->len > 0) + { + g_string_append_printf(smb_conf_new, "\tguest ok = %s\n",share->guest_ok->str); + } + } + + /* Write new share to smb.conf */ + write_smbconf(smb_conf_new->str); + + fclose(smb_file); + + g_free(line); + g_free(tmp); + + g_string_free(smb_conf_new,TRUE); + + return 0; +} + + + +/** +* Function erase shared section containing path from smb.conf +* shared_items must by actual! +*/ +gint delete_share (GPtrArray *shared_items, const gchar *path) +{ + FILE *smb_file; /* Samba config file */ + GString *smb_conf_new; /* Content of smb.conf */ + gchar *line; /* Line buffer */ + gchar *orig; /* Original line */ + TSmbConfItem *skip_item; /* Skip this share */ + gboolean skip = FALSE; /* Skip lines (erase from config) */ + + skip_item = is_shared_item(shared_items, path); + + if(!skip_item) + { + g_warning ("Directory \"%s\" is NOT shared",path); + return ERROR_DIRECTORY_NOT_SHARED; + } + + + /* smb.conf - File exist test */ + if(!g_file_test(smb_conf_path, G_FILE_TEST_EXISTS)) + { + g_warning ("Config file \"%s\" does not exist!", smb_conf_path); + return ERROR_FILE_NOT_EXIST; + } + + /* Try open smb.conf - rewrite all */ + smb_file = fopen(smb_conf_path, "r"); + if(smb_file == NULL) + { + g_warning ("Can not open file \"%s\"!", smb_conf_path); + return ERROR_CAN_NOT_OPEN_FILE; + } + + /* Inicialize buffers */ + smb_conf_new = g_string_new(""); + line = g_strnfill(BUFSIZ, '\0'); + orig = g_strnfill(BUFSIZ, '\0'); + + + /* Load smb.conf WITHOUT section skip_name (section containing path) */ + while(fgets(line, BUFSIZ, smb_file)) + { + g_stpcpy(orig, line); + + /* Remove white space */ + g_strstrip(line); + + if(line[0] == '[') + { + skip = FALSE; + + /* Test special sections */ + if(strstr(line,skip_item->name->str)) + { + skip = TRUE; + } + } + + if(!skip) + { + g_string_append(smb_conf_new,orig); + } + } + + /* Write deleted share to smb.conf */ + write_smbconf(smb_conf_new->str); + + fclose(smb_file); + + g_free(line); + g_free(orig); + + g_string_free (smb_conf_new,TRUE); + + return OK; +} + +void item_to_strv (TSmbConfItem *item, gchar ***ret) +{ + /* [share name], "path =", "commennt =", "read only =", "guest ok =" */ + + *ret = g_new (gchar *, 6); + + (*ret)[0] = g_strdup (item->name->str); + (*ret)[1] = g_strdup (item->path->str); + (*ret)[2] = g_strdup (item->comment->str); + (*ret)[3] = g_strdup (item->read_only->str); + (*ret)[4] = g_strdup (item->guest_ok->str); + + (*ret)[5] = NULL; +} + + + +void char_to_strv(const gchar *str, gchar ***ret) +{ + *ret = g_new (char *, 2); + + (*ret)[0] = g_strdup (str); + (*ret)[1] = NULL; +} + + +/** +* If path is shared then returns share parameters in result. +*/ +gint +smb_get_share_status (const gchar *path, gchar ***result) +{ + gboolean found = FALSE; + GPtrArray *shared_items = shared_items_array_new(); + + Error_sfshare err; + + err = load_smb_conf (shared_items); + + if (err != OK) + { + /* Free */ + shared_items_array_free (shared_items); + return err; + } + + + TSmbConfItem *test; + gint i; + for (i = 0; i < shared_items->len; i++) + { + test = g_ptr_array_index(shared_items, i); + if (!g_strcmp0(test->path->str,path)) + { + found = TRUE; /* Path found in smb.conf */ + break; + } + } + + if (found) + item_to_strv(test, result); + else + char_to_strv(NULL,result); + + /* Free */ + shared_items_array_free (shared_items); + + return OK; +} + + +/** +* Write share to smb.conf +*/ +gint +smb_set_share (gchar **parameters) +{ + gint ret = OK; + /* Create new items array */ + GPtrArray *shared_items = shared_items_array_new (); + + /* Load share sections from smb.conf */ + ret = load_smb_conf (shared_items); + + /* Create share item */ + /* [share name], "path =", "commennt =", "read only =", "guest ok =" */ + TSmbConfItem *item = smbconf_item_new (parameters[0], parameters[1], parameters[2], parameters[3], parameters[4]); + + /* Write share to smb.conf */ + if(ret == OK) + ret = write_share (shared_items, item); + + /* free */ + smbconf_item_free (item); + shared_items_array_free (shared_items); + + return ret; +} + + +/** +* Delete share section from smb.conf +*/ +gint +smb_delete_share (gchar **path) +{ + gint ret = OK; + /* Create new items array */ + GPtrArray *shared_items = shared_items_array_new (); + + /* Load share sections from smb.conf */ + ret = load_smb_conf (shared_items); + + /* try to delete shared section */ + if(ret == OK) + ret = delete_share (shared_items, path[0]); + + /* Free */ + shared_items_array_free (shared_items); + + return ret; +} + |