You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
freshtomato-arm/release/src-rt-6.x.4708/router/rc/samba.c

401 lines
11 KiB
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 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
*
*/
/*
*
* FreshTomato Firmware
* Fixes/updates (C) 2018 - 2023 pedro
*
*/
#include "rc.h"
#include <string.h>
#include <wlutils.h>
#include <dirent.h>
#include <linux/version.h>
#define samba_dir "/etc/samba"
#define samba_var_dir "/var/run/samba"
#define samba_configfile samba_dir"/smb.conf"
/* needed by logmsg() */
#define LOGMSG_DISABLE DISABLE_SYSLOG_OSM
#define LOGMSG_NVDEBUG "samba_debug"
static void stop_wsdd(void)
{
killall_tk_period_wait("wsdd2", 50);
}
static void start_wsdd(void)
{
unsigned char ea[ETHER_ADDR_LEN];
char serial[18];
char bootparms[64];
stop_wsdd();
if (!ether_atoe(nvram_safe_get("lan_hwaddr"), ea))
f_read("/dev/urandom", ea, sizeof(ea));
snprintf(serial, sizeof(serial), "%02x%02x%02x%02x%02x%02x", ea[0], ea[1], ea[2], ea[3], ea[4], ea[5]);
snprintf(bootparms, sizeof(bootparms), "sku:%s,serial:%s", (nvram_get("odmpid") ? : "FreshTomato"), serial);
/* (-i: no multi-interface binds atm) */
eval("wsdd2", "-d", "-w", "-i", nvram_safe_get("lan_ifname"), "-b", bootparms);
}
static void kill_samba(int sig)
{
if (sig == SIGTERM) {
killall_tk_period_wait("smbd", 50);
killall_tk_period_wait("nmbd", 50);
}
else {
killall("smbd", sig);
killall("nmbd", sig);
}
}
#if defined(TCONFIG_BCMARM) && defined(TCONFIG_GROCTRL)
static void enable_gro(int interval)
{
char *argv[3] = { "echo", "", NULL };
char lan_ifname[32], *lan_ifnames, *next;
char path[64];
char parm[32];
if (nvram_get_int("gro_disable"))
return;
/* enabled gro on vlan interface */
lan_ifnames = nvram_safe_get("lan_ifnames");
foreach(lan_ifname, lan_ifnames, next) {
if (!strncmp(lan_ifname, "vlan", 4)) {
memset(path, 0, sizeof(path));
snprintf(path, sizeof(path), ">>/proc/net/vlan/%s", lan_ifname);
memset(parm, 0, sizeof(parm));
snprintf(parm, sizeof(parm), "-gro %d", interval);
argv[1] = parm;
_eval(argv, path, 0, NULL);
}
}
}
#endif
void start_samba(int force)
{
FILE *fp;
DIR *dir = NULL;
struct dirent *dp;
char nlsmod[16];
int mode;
char *nv;
char *si;
char *buf;
char *p, *q;
char *name, *path, *comment, *writeable, *hidden;
int cnt = 0, i;
char *smbd_user;
int ret1 = 0, ret2 = 0;
char buffer[32], buffer2[8], buffer3[32];
#if defined(TCONFIG_BCMARM) && defined(TCONFIG_BCMSMP)
int cpu_num = sysconf(_SC_NPROCESSORS_CONF);
int taskset_ret = -1;
#endif
/* only if enabled or forced and lan_hostname is set */
mode = nvram_get_int("smbd_enable");
if ((!mode && force == 0) || (!nvram_invmatch("lan_hostname", "")))
return;
if (pidof("nmbd") > 0) {
logmsg(LOG_WARNING, "service nmbd already running");
return;
}
if (serialize_restart("smbd", 1))
return;
mkdir_if_none(samba_var_dir);
mkdir_if_none(samba_dir);
if ((fp = fopen(samba_configfile, "w")) == NULL) {
logerr(__FUNCTION__, __LINE__, samba_configfile);
return;
}
#ifdef TCONFIG_BCMARM
/* check samba enabled ? */
if (mode)
nvram_set("txworkq", "1"); /* set txworkq to 1, see et/sys/et_linux.c */
else
nvram_unset("txworkq");
#ifdef TCONFIG_GROCTRL
/* enable / disable gro via GUI nas-samba.asp; Default: off */
enable_gro(2);
#endif
#endif
si = nvram_safe_get("smbd_ifnames");
if (strlen(si)) {
memset(buffer3, 0, sizeof(buffer3)); /* reset */
for (i = 0; i < BRIDGE_COUNT; i++) {
memset(buffer, 0, sizeof(buffer)); /* reset */
snprintf(buffer, sizeof(buffer), (i == 0 ? "lan_ifname" : "lan%d_ifname"), i);
memset(buffer2, 0, sizeof(buffer2)); /* reset */
snprintf(buffer2, sizeof(buffer2), "br%d", i);
if ((strlen(nvram_safe_get(buffer)) > 0) && (strstr(si, buffer2) != NULL)) { /* bridge is up & present in 'smbd_ifnames' */
if (strlen(buffer3) > 0)
strlcat(buffer3, " ", sizeof(buffer3));
strlcat(buffer3, buffer2, sizeof(buffer3));
}
}
si = buffer3;
}
fprintf(fp, "[global]\n");
nv = nvram_safe_get("smbd_custom");
/* add interfaces options unless overriden by the user */
if (strstr(nv, "interfaces") == NULL)
fprintf(fp, " interfaces = %s\n", strlen(si) ? si : nvram_safe_get("lan_ifname"));
fprintf(fp, " bind interfaces only = yes\n"
" enable core files = no\n"
" deadtime = 30\n"
" smb encrypt = disabled\n"
" min receivefile size = 16384\n"
" workgroup = %s\n"
" netbios name = %s\n"
" server string = FreshTomato Samba Server\n"
" dos charset = ASCII\n"
" unix charset = UTF8\n"
" display charset = UTF8\n"
" guest account = nobody\n"
" security = user\n"
" %s\n"
" guest ok = %s\n"
" guest only = no\n"
" browseable = yes\n"
" timestamp logs = no\n"
" passdb backend = smbpasswd\n"
" encrypt passwords = yes\n"
" preserve case = yes\n"
" short preserve case = yes\n",
nvram_get("smbd_wgroup") ? : "WORKGROUP",
nvram_safe_get("lan_hostname"),
mode == 2 ? "" : "map to guest = Bad User",
mode == 2 ? "no" : "yes"); /* guest ok */
fprintf(fp, " map archive = no\n"
" map hidden = no\n"
" map read only = no\n"
" map system = no\n"
#ifndef TCONFIG_BCMARM
" load printers = no\n" /* add for Samba printcap issue (MIPS only) */
" printing = bsd\n"
" printcap name = /dev/null\n"
#endif
" store dos attributes = no\n"
" dos filemode = yes\n"
" strict locking = no\n"
" oplocks = yes\n"
" level2 oplocks = yes\n"
" kernel oplocks = no\n"
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)
" use sendfile = no\n");
#else
" use sendfile = yes\n");
#endif
if (nvram_get_int("smbd_wins")) {
nv = nvram_safe_get("wan_wins");
if ((!*nv) || (strcmp(nv, "0.0.0.0") == 0))
fprintf(fp, " wins support = yes\n");
}
/* 0 - smb1, 1 - smb2, 2 - smb1 + smb2 */
if (nvram_get_int("smbd_protocol") == 0)
fprintf(fp, " max protocol = NT1\n");
else
fprintf(fp, " max protocol = SMB2\n");
if (nvram_get_int("smbd_protocol") == 1)
fprintf(fp, " min protocol = SMB2\n");
if (nvram_get_int("smbd_master")) {
fprintf(fp,
" domain master = yes\n"
" local master = yes\n"
" preferred master = yes\n"
" os level = 255\n");
}
nv = nvram_safe_get("smbd_cpage");
if (*nv) {
memset(nlsmod, 0, sizeof(nlsmod));
snprintf(nlsmod, sizeof(nlsmod), "nls_cp%s", nv);
nv = nvram_safe_get("smbd_nlsmod");
if ((*nv) && (strcmp(nv, nlsmod) != 0))
modprobe_r(nv);
modprobe(nlsmod);
nvram_set("smbd_nlsmod", nlsmod);
}
nv = nvram_safe_get("smbd_custom");
/* add socket options unless overriden by the user */
if (strstr(nv, "socket options") == NULL)
fprintf(fp, " socket options = TCP_NODELAY SO_KEEPALIVE IPTOS_LOWDELAY SO_RCVBUF=65536 SO_SNDBUF=65536\n");
fprintf(fp, "%s\n", nv);
/* configure shares */
if ((buf = strdup(nvram_safe_get("smbd_shares"))) && (*buf)) {
/* sharename<path<comment<writeable[0|1]<hidden[0|1] */
p = buf;
while ((q = strsep(&p, ">")) != NULL) {
if (vstrsep(q, "<", &name, &path, &comment, &writeable, &hidden) < 5)
continue;
if (!path || !name)
continue;
/* share name */
fprintf(fp, "\n[%s]\n", name);
/* path */
fprintf(fp, " path = %s\n", path);
/* access level */
if (!strcmp(writeable, "1"))
fprintf(fp, " writable = yes\n delete readonly = yes\n force user = root\n");
if (!strcmp(hidden, "1"))
fprintf(fp, " browseable = no\n");
/* comment */
if (comment)
fprintf(fp, " comment = %s\n", comment);
cnt++;
}
free(buf);
}
/* share every mountpoint below MOUNT_ROOT */
if (nvram_get_int("smbd_autoshare") && (dir = opendir(MOUNT_ROOT))) {
while ((dp = readdir(dir))) {
if (strcmp(dp->d_name, ".") && strcmp(dp->d_name, "..")) {
/* only if is a directory and is mounted */
if (!dir_is_mountpoint(MOUNT_ROOT, dp->d_name))
continue;
/* smbd_autoshare: 0 - disable, 1 - read-only, 2 - writable, 3 - hidden writable */
fprintf(fp, "\n[%s]\n path = %s/%s\n comment = %s\n", dp->d_name, MOUNT_ROOT, dp->d_name, dp->d_name);
if (nvram_match("smbd_autoshare", "3")) /* hidden */
fprintf(fp, "\n[%s$]\n path = %s/%s\n browseable = no\n", dp->d_name, MOUNT_ROOT, dp->d_name);
if ((nvram_match("smbd_autoshare", "2")) || (nvram_match("smbd_autoshare", "3"))) /* RW */
fprintf(fp, " writable = yes\n delete readonly = yes\n force user = root\n");
cnt++;
}
}
}
if (dir)
closedir(dir);
if (cnt == 0)
/* by default share MOUNT_ROOT as read-only */
fprintf(fp, "\n[share]\n"
" path = %s\n"
" writable = no\n",
MOUNT_ROOT);
fclose(fp);
/* write smbpasswd */
eval("smbpasswd", "nobody", "\"\"");
if (mode == 2) {
smbd_user = nvram_safe_get("smbd_user");
if ((!*smbd_user) || (!strcmp(smbd_user, "root")))
smbd_user = "nas";
eval("smbpasswd", smbd_user, nvram_safe_get("smbd_passwd"));
}
kill_samba(SIGHUP);
/* start samba */
ret1 = eval("nmbd", "-D");
#if defined(TCONFIG_BCMARM) && defined(TCONFIG_BCMSMP)
if (cpu_num > 1)
taskset_ret = cpu_eval(NULL, "1", "ionice", "-c1", "-n0", "smbd", "-D");
else
taskset_ret = eval("ionice", "-c1", "-n0", "smbd", "-D");
if (taskset_ret != 0)
#endif
ret2 = eval("smbd", "-D");
if (ret1 || ret2) {
kill_samba(SIGTERM);
logmsg(LOG_ERR, "starting samba daemon failed ...");
}
else {
start_wsdd();
logmsg(LOG_INFO, "samba daemon is started");
}
}
void stop_samba(void)
{
if (serialize_restart("smbd", 0))
return;
stop_wsdd();
/* stop samba */
if ((pidof("smbd") > 0 ) || (pidof("nmbd") > 0 )) {
kill_samba(SIGTERM);
logmsg(LOG_INFO, "samba daemon is stopped");
}
/* clean up */
unlink("/var/log/log.smbd");
unlink("/var/log/log.nmbd");
eval("rm", "-rf", "/var/nmbd");
eval("rm", "-rf", "/var/log/cores");
// eval("rm", "-rf", samba_dir); /* see: https://bitbucket.org/pedro311/freshtomato-arm/issues/349/samba-file-cleanup-prevents-adding */
eval("rm", "-rf", samba_var_dir);
#if defined(TCONFIG_BCMARM) && defined(TCONFIG_GROCTRL)
enable_gro(0);
#endif
}