1/*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License as
4 * published by the Free Software Foundation; either version 2 of
5 * the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
15 * MA 02111-1307 USA
16 */
17
18#include <stdio.h>
19#include <string.h>
20#include <stdlib.h>
21#include <dirent.h>
22#include <unistd.h>
23#include <ctype.h>
24#include <bcmnvram.h>
25#include <shutils.h>
26#include <rtconfig.h>
27
28#include "usb_info.h"
29#include "disk_initial.h"
30#include "disk_share.h"
31
32#include <linux/version.h>
33
34#define SAMBA_CONF "/etc/smb.conf"
35
36/* @return:
37 * 	If mount_point is equal to one of partition of all disks case-insensitivity, return true.
38 */
39static int check_mount_point_icase(const disk_info_t *d_info, const partition_info_t *p_info, const disk_info_t *disk, const u32 part_nr, const char *m_point)
40{
41	int v = 0;
42	const disk_info_t *d;
43	const partition_info_t *p;
44
45	if (!d_info || !p_info || !disk || part_nr > 15 || !m_point || *m_point == '\0')
46		return 0;
47
48	for (d = d_info; !v && d != NULL; d = d->next) {
49		for (p = d->partitions; !v && p != NULL; p = p->next) {
50			if (!p->mount_point || (d == disk && p->partition_order == part_nr))
51				continue;
52
53			if (strcasecmp(p->mount_point, m_point))
54				continue;
55
56			v = 1;
57		}
58	}
59
60	return v;
61}
62
63int
64is_invalid_char_for_hostname(char c)
65{
66	int ret = 0;
67
68	if (c < 0x20)
69		ret = 1;
70	else if (c >= 0x21 && c <= 0x2c)
71		ret = 1;
72	else if (c >= 0x2e && c <= 0x2f)
73		ret = 1;
74	else if (c >= 0x3a && c <= 0x40)
75		ret = 1;
76#if 0
77	else if (c >= 0x5b && c <= 0x60)
78		ret = 1;
79#else	/* allow '_' */
80	else if (c >= 0x5b && c <= 0x5e)
81		ret = 1;
82	else if (c == 0x60)
83		ret = 1;
84#endif
85	else if (c >= 0x7b)
86		ret = 1;
87#if 0
88	printf("%c (0x%02x) is %svalid for hostname\n", c, c, (ret == 0) ? "  " : "in");
89#endif
90	return ret;
91}
92
93int
94is_valid_hostname(const char *name)
95{
96	int ret = 1, len, i;
97
98	if (!name)
99		return 0;
100
101	len = strlen(name);
102	if (len == 0)
103	{
104		ret = 0;
105		goto ENDERR;
106	}
107
108	for (i = 0; i < len ; i++)
109		if (is_invalid_char_for_hostname(name[i]))
110		{
111			ret = 0;
112			break;
113		}
114
115ENDERR:
116#if 0
117	printf("%s is %svalid for hostname\n", name, (ret == 1) ? "  " : "in");
118#endif
119	return ret;
120}
121
122/* For NETBIOS name,
123 * 1. NetBIOS names are a sequence of alphanumeric characters.
124 * 2. The hyphen ("-") and full-stop (".") characters may also be used
125 *     in the NetBIOS name, but not as the first or last character.
126 * 3. The NetBIOS name is 16 ASCII characters, however Microsoft limits
127 *     the host name to 15 characters and reserves the 16th character
128 *     as a NetBIOS Suffix
129 */
130int
131is_valid_netbios_name(const char *name)
132{
133	int i, valid = 1;
134	size_t len;
135
136	if (!name)
137		return 0;
138
139	len = strlen(name);
140	if (!len || len > 15)
141		return 0;
142
143	for (i = 0; valid && i < len; ++i) {
144		if (isalnum(name[i]))
145			continue;
146		else if ((name[i] == '-' || name[i] == '.') && (i > 0 && i < (len - 1)))
147			continue;
148
149		valid = 0;
150	}
151
152	return valid;
153}
154
155int check_existed_share(const char *string)
156{
157	FILE *tp;
158	char buf[PATH_MAX], target[256];
159
160	if((tp = fopen(SAMBA_CONF, "r")) == NULL)
161		return 0;
162
163	if(string == NULL || strlen(string) <= 0)
164		return 0;
165
166	memset(target, 0, 256);
167	sprintf(target, "[%s]", string);
168
169	memset(buf, 0, PATH_MAX);
170	while(fgets(buf, sizeof(buf), tp) != NULL){
171		if(strstr(buf, target)){
172			fclose(tp);
173			return 1;
174		}
175	}
176
177	fclose(tp);
178	return 0;
179}
180
181int get_list_strings_count(char **list, int size, char *str)
182{
183	int i, count = 0;
184
185	for (i = 0; i < size; i++)
186		if (strcmp(list[i], str) == 0) count++;
187	return count;
188}
189
190int main(int argc, char *argv[])
191{
192	FILE *fp;
193	int n=0;
194	char *p_computer_name = NULL;
195	disk_info_t *follow_disk, *disks_info = NULL;
196	partition_info_t *follow_partition;
197	char *mount_folder;
198	int result, node_layer, samba_right;
199	int sh_num;
200	char **folder_list = NULL;
201	int acc_num;
202	char **account_list;
203	int dup, same_m_pt = 0;
204	char unique_share_name[PATH_MAX];
205
206	unlink("/var/log.samba");
207
208	if ((fp=fopen(SAMBA_CONF, "r"))) {
209		fclose(fp);
210		unlink(SAMBA_CONF);
211	}
212
213	if((fp = fopen(SAMBA_CONF, "w")) == NULL)
214		goto confpage;
215
216	fprintf(fp, "[global]\n");
217	if (nvram_safe_get("st_samba_workgroup"))
218		fprintf(fp, "workgroup = %s\n", nvram_safe_get("st_samba_workgroup"));
219#if 0
220	if (nvram_safe_get("computer_name")) {
221		fprintf(fp, "netbios name = %s\n", nvram_safe_get("computer_name"));
222		fprintf(fp, "server string = %s\n", nvram_safe_get("computer_name"));
223	}
224#else
225	p_computer_name = nvram_get("computer_name") && is_valid_netbios_name(nvram_get("computer_name")) ? nvram_get("computer_name") : get_productid();
226	if (p_computer_name) {
227		fprintf(fp, "netbios name = %s\n", p_computer_name);
228		fprintf(fp, "server string = %s\n", p_computer_name);
229	}
230#endif
231
232	fprintf(fp, "unix charset = UTF8\n");		// ASUS add
233	fprintf(fp, "display charset = UTF8\n");	// ASUS add
234	fprintf(fp, "log file = /var/log.samba\n");
235	fprintf(fp, "log level = 0\n");
236	fprintf(fp, "max log size = 5\n");
237
238	// account mode
239	if(nvram_match("st_samba_mode", "2") || nvram_match("st_samba_mode", "4")
240			|| (nvram_match("st_samba_mode", "1") && nvram_get("st_samba_force_mode") == NULL)
241			){
242		fprintf(fp, "security = USER\n");
243		fprintf(fp, "guest ok = no\n");
244		fprintf(fp, "map to guest = Bad User\n");
245	}
246	// share mode
247	else if (nvram_match("st_samba_mode", "1") || nvram_match("st_samba_mode", "3")) {
248#if 0
249//#if defined(RTCONFIG_TFAT) || defined(RTCONFIG_TUXERA_NTFS) || defined(RTCONFIG_TUXERA_HFS)
250		if(nvram_get_int("enable_samba_tuxera") == 1){
251			fprintf(fp, "auth methods = guest\n");
252			fprintf(fp, "guest account = admin\n");
253			fprintf(fp, "map to guest = Bad Password\n");
254			fprintf(fp, "guest ok = yes\n");
255		}
256		else{
257			fprintf(fp, "security = SHARE\n");
258			fprintf(fp, "guest only = yes\n");
259		}
260#else
261		fprintf(fp, "security = SHARE\n");
262		fprintf(fp, "guest only = yes\n");
263#endif
264	}
265	else{
266		usb_dbg("samba mode: no\n");
267		goto confpage;
268	}
269
270	fprintf(fp, "encrypt passwords = yes\n");
271	fprintf(fp, "pam password change = no\n");
272	fprintf(fp, "null passwords = yes\n");		// ASUS add
273
274	fprintf(fp, "force directory mode = 0777\n");
275	fprintf(fp, "force create mode = 0777\n");
276
277	/* max users */
278	if (strcmp(nvram_safe_get("st_max_user"), "") != 0)
279		fprintf(fp, "max connections = %s\n", nvram_safe_get("st_max_user"));
280
281	/* remove socket options due to NIC compatible issue */
282	if(!nvram_get_int("stop_samba_speedup")){
283#ifdef RTCONFIG_BCMARM
284#ifdef RTCONFIG_BCM_7114
285		fprintf(fp, "socket options = IPTOS_LOWDELAY TCP_NODELAY SO_RCVBUF=131072 SO_SNDBUF=131072\n");
286#endif
287#else
288		fprintf(fp, "socket options = TCP_NODELAY SO_KEEPALIVE SO_RCVBUF=65536 SO_SNDBUF=65536\n");
289#endif
290	}
291	fprintf(fp, "obey pam restrictions = no\n");
292	fprintf(fp, "use spnego = no\n");		// ASUS add
293	fprintf(fp, "client use spnego = no\n");	// ASUS add
294//	fprintf(fp, "client use spnego = yes\n");	// ASUS add
295	fprintf(fp, "disable spoolss = yes\n");		// ASUS add
296	fprintf(fp, "host msdfs = no\n");		// ASUS add
297	fprintf(fp, "strict allocate = No\n");		// ASUS add
298//	fprintf(fp, "mangling method = hash2\n");	// ASUS add
299	fprintf(fp, "wide links = no\n"); 		// ASUS add
300	fprintf(fp, "bind interfaces only = yes\n");	// ASUS add
301#ifndef RTCONFIG_BCMARM
302	fprintf(fp, "interfaces = lo br0 %s\n", (is_routing_enabled() && nvram_get_int("smbd_wanac")) ? nvram_safe_get("wan0_ifname") : "");
303#else
304	fprintf(fp, "interfaces = br0 %s/%s %s\n", nvram_safe_get("lan_ipaddr"), nvram_safe_get("lan_netmask"), (is_routing_enabled() && nvram_get_int("smbd_wanac")) ? nvram_safe_get("wan0_ifname") : "");
305#endif
306#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)
307	fprintf(fp, "use sendfile = no\n");
308#else
309	fprintf(fp, "use sendfile = yes\n");
310#endif
311#ifdef RTCONFIG_RECVFILE
312	if(!nvram_get_int("stop_samba_recv"))
313		fprintf(fp, "use recvfile = yes\n");
314#endif
315
316	fprintf(fp, "map archive = no\n");
317	fprintf(fp, "map hidden = no\n");
318	fprintf(fp, "map read only = no\n");
319	fprintf(fp, "map system = no\n");
320	fprintf(fp, "store dos attributes = yes\n");
321	fprintf(fp, "dos filemode = yes\n");
322	fprintf(fp, "oplocks = yes\n");
323	fprintf(fp, "level2 oplocks = yes\n");
324	fprintf(fp, "kernel oplocks = no\n");
325
326	disks_info = read_disk_data();
327	if (disks_info == NULL) {
328		usb_dbg("Couldn't get disk list when writing smb.conf!\n");
329		goto confpage;
330	}
331
332	/* share */
333	if (nvram_match("st_samba_mode", "0") || !strcmp(nvram_safe_get("st_samba_mode"), "")) {
334		;
335	}
336	else if (nvram_match("st_samba_mode", "1") && nvram_match("st_samba_force_mode", "1")) {
337		usb_dbg("samba mode: share\n");
338
339		for (follow_disk = disks_info; follow_disk != NULL; follow_disk = follow_disk->next) {
340			for (follow_partition = follow_disk->partitions; follow_partition != NULL; follow_partition = follow_partition->next) {
341				if (follow_partition->mount_point == NULL)
342					continue;
343
344				strcpy(unique_share_name, follow_partition->mount_point);
345				do {
346					dup = check_mount_point_icase(disks_info, follow_partition, follow_disk, follow_partition->partition_order, unique_share_name);
347					if (dup)
348						sprintf(unique_share_name, "%s(%d)", follow_partition->mount_point, ++same_m_pt);
349				} while (dup);
350				mount_folder = strrchr(unique_share_name, '/')+1;
351
352				fprintf(fp, "[%s]\n", mount_folder);
353				fprintf(fp, "comment = %s's %s\n", follow_disk->tag, mount_folder);
354				fprintf(fp, "veto files = /.__*.txt*/asusware*/asus_lighttpdpasswd/\n");
355				fprintf(fp, "path = %s\n", follow_partition->mount_point);
356				fprintf(fp, "writeable = yes\n");
357
358				fprintf(fp, "dos filetimes = yes\n");
359				fprintf(fp, "fake directory create times = yes\n");
360			}
361		}
362	}
363	else if (nvram_match("st_samba_mode", "2")) {
364		usb_dbg("samba mode: share\n");
365
366		for (follow_disk = disks_info; follow_disk != NULL; follow_disk = follow_disk->next) {
367			for (follow_partition = follow_disk->partitions; follow_partition != NULL; follow_partition = follow_partition->next) {
368				if (follow_partition->mount_point == NULL)
369					continue;
370
371				strcpy(unique_share_name, follow_partition->mount_point);
372				do {
373					dup = check_mount_point_icase(disks_info, follow_partition, follow_disk, follow_partition->partition_order, unique_share_name);
374					if (dup)
375						sprintf(unique_share_name, "%s(%d)", follow_partition->mount_point, ++same_m_pt);
376				} while (dup);
377				mount_folder = strrchr(unique_share_name, '/')+1;
378
379				node_layer = get_permission(NULL, follow_partition->mount_point, NULL, "cifs");
380				if(node_layer == 3){
381					fprintf(fp, "[%s]\n", mount_folder);
382					fprintf(fp, "comment = %s's %s\n", follow_disk->tag, mount_folder);
383					fprintf(fp, "path = %s\n", follow_partition->mount_point);
384					fprintf(fp, "writeable = yes\n");
385
386					fprintf(fp, "dos filetimes = yes\n");
387					fprintf(fp, "fake directory create times = yes\n");
388				}
389				else{
390					//result = get_all_folder(follow_partition->mount_point, &sh_num, &folder_list);
391					result = get_folder_list(follow_partition->mount_point, &sh_num, &folder_list);
392					if (result < 0){
393						free_2_dimension_list(&sh_num, &folder_list);
394						continue;
395					}
396
397					for (n = 0; n < sh_num; ++n){
398						samba_right = get_permission(NULL, follow_partition->mount_point, folder_list[n], "cifs");
399						if (samba_right < 0 || samba_right > 3)
400							samba_right = DEFAULT_SAMBA_RIGHT;
401
402						if(samba_right > 0){
403							int count = get_list_strings_count(folder_list, sh_num, folder_list[n]);
404							if (count <= 1)
405								fprintf(fp, "[%s]\n", folder_list[n]);
406							else
407								fprintf(fp, "[%s (at %s)]\n", folder_list[n], mount_folder);
408							fprintf(fp, "comment = %s's %s in %s\n", mount_folder, folder_list[n], follow_disk->tag);
409							fprintf(fp, "path = %s/%s\n", follow_partition->mount_point, folder_list[n]);
410							if(samba_right == 3)
411								fprintf(fp, "writeable = yes\n");
412							else
413								fprintf(fp, "writeable = no\n");
414
415							fprintf(fp, "dos filetimes = yes\n");
416							fprintf(fp, "fake directory create times = yes\n");
417						}
418					}
419
420					free_2_dimension_list(&sh_num, &folder_list);
421				}
422			}
423		}
424	}
425	else if (nvram_match("st_samba_mode", "3")) {
426		usb_dbg("samba mode: user\n");
427
428		// get the account list
429		if (get_account_list(&acc_num, &account_list) < 0) {
430			usb_dbg("Can't read the account list.\n");
431			free_2_dimension_list(&acc_num, &account_list);
432			goto confpage;
433		}
434
435		for (follow_disk = disks_info; follow_disk != NULL; follow_disk = follow_disk->next) {
436			for (follow_partition = follow_disk->partitions; follow_partition != NULL; follow_partition = follow_partition->next) {
437				if (follow_partition->mount_point == NULL)
438					continue;
439
440				mount_folder = strrchr(follow_partition->mount_point, '/')+1;
441
442				// 1. get the folder list
443				if (get_folder_list(follow_partition->mount_point, &sh_num, &folder_list) < 0) {
444					free_2_dimension_list(&sh_num, &folder_list);
445				}
446
447				// 2. start to get every share
448				for (n = -1; n < sh_num; ++n) {
449					int i, first;
450
451					if(n == -1){
452						fprintf(fp, "[%s]\n", mount_folder);
453						fprintf(fp, "comment = %s's %s\n", follow_disk->tag, mount_folder);
454						fprintf(fp, "path = %s\n", follow_partition->mount_point);
455					}
456					else{
457						int count = get_list_strings_count(folder_list, sh_num, folder_list[n]);
458						if (count <= 1)
459							fprintf(fp, "[%s]\n", folder_list[n]);
460						else
461							fprintf(fp, "[%s (at %s)]\n", folder_list[n], mount_folder);
462						fprintf(fp, "comment = %s's %s in %s\n", mount_folder, folder_list[n], follow_disk->tag);
463						fprintf(fp, "path = %s/%s\n", follow_partition->mount_point, folder_list[n]);
464					}
465
466					fprintf(fp, "dos filetimes = yes\n");
467					fprintf(fp, "fake directory create times = yes\n");
468
469					fprintf(fp, "valid users = ");
470					first = 1;
471					for (i = 0; i < acc_num; ++i) {
472						if(n == -1)
473							samba_right = get_permission(account_list[i], follow_partition->mount_point, NULL, "cifs");
474						else
475							samba_right = get_permission(account_list[i], follow_partition->mount_point, folder_list[n], "cifs");
476						if (first == 1)
477							first = 0;
478						else
479							fprintf(fp, ", ");
480
481						fprintf(fp, "%s", account_list[i]);
482					}
483					fprintf(fp, "\n");
484
485					fprintf(fp, "invalid users = ");
486					first = 1;
487					for (i = 0; i < acc_num; ++i) {
488						if(n == -1)
489							samba_right = get_permission(account_list[i], follow_partition->mount_point, NULL, "cifs");
490						else
491							samba_right = get_permission(account_list[i], follow_partition->mount_point, folder_list[n], "cifs");
492						if (samba_right >= 1)
493							continue;
494
495						if (first == 1)
496							first = 0;
497						else
498							fprintf(fp, ", ");
499
500						fprintf(fp, "%s", account_list[i]);
501					}
502					fprintf(fp, "\n");
503
504					fprintf(fp, "read list = ");
505					first = 1;
506					for (i = 0; i < acc_num; ++i) {
507						if(n == -1)
508							samba_right = get_permission(account_list[i], follow_partition->mount_point, NULL, "cifs");
509						else
510							samba_right = get_permission(account_list[i], follow_partition->mount_point, folder_list[n], "cifs");
511						if (samba_right < 1)
512							continue;
513
514						if (first == 1)
515							first = 0;
516						else
517							fprintf(fp, ", ");
518
519						fprintf(fp, "%s", account_list[i]);
520					}
521					fprintf(fp, "\n");
522
523					fprintf(fp, "write list = ");
524					first = 1;
525					for (i = 0; i < acc_num; ++i) {
526						if(n == -1)
527							samba_right = get_permission(account_list[i], follow_partition->mount_point, NULL, "cifs");
528						else
529							samba_right = get_permission(account_list[i], follow_partition->mount_point, folder_list[n], "cifs");
530						if (samba_right < 2)
531							continue;
532
533						if (first == 1)
534							first = 0;
535						else
536							fprintf(fp, ", ");
537
538						fprintf(fp, "%s", account_list[i]);
539					}
540					fprintf(fp, "\n");
541				}
542
543				free_2_dimension_list(&sh_num, &folder_list);
544			}
545		}
546
547		free_2_dimension_list(&acc_num, &account_list);
548	}
549	else if (nvram_match("st_samba_mode", "4")
550			|| (nvram_match("st_samba_mode", "1") && nvram_get("st_samba_force_mode") == NULL)
551			) {
552		usb_dbg("samba mode: user\n");
553
554		// get the account list
555		if (get_account_list(&acc_num, &account_list) < 0) {
556			usb_dbg("Can't read the account list.\n");
557			free_2_dimension_list(&acc_num, &account_list);
558			goto confpage;
559		}
560
561		for (follow_disk = disks_info; follow_disk != NULL; follow_disk = follow_disk->next) {
562			for (follow_partition = follow_disk->partitions; follow_partition != NULL; follow_partition = follow_partition->next) {
563				if (follow_partition->mount_point == NULL)
564					continue;
565
566				mount_folder = strrchr(follow_partition->mount_point, '/')+1;
567
568				// 1. get the folder list
569				if (get_folder_list(follow_partition->mount_point, &sh_num, &folder_list) < 0) {
570					free_2_dimension_list(&sh_num, &folder_list);
571				}
572
573				// 2. start to get every share
574				for (n = 0; n < sh_num; ++n) {
575					int i, first;
576
577					int count = get_list_strings_count(folder_list, sh_num, folder_list[n]);
578					if (count <= 1)
579						fprintf(fp, "[%s]\n", folder_list[n]);
580					else
581						fprintf(fp, "[%s (at %s)]\n", folder_list[n], mount_folder);
582					fprintf(fp, "comment = %s's %s in %s\n", mount_folder, folder_list[n], follow_disk->tag);
583					fprintf(fp, "path = %s/%s\n", follow_partition->mount_point, folder_list[n]);
584
585					fprintf(fp, "dos filetimes = yes\n");
586					fprintf(fp, "fake directory create times = yes\n");
587
588					fprintf(fp, "valid users = ");
589					first = 1;
590					for (i = 0; i < acc_num; ++i) {
591						if(n == -1)
592							samba_right = get_permission(account_list[i], follow_partition->mount_point, NULL, "cifs");
593						else
594							samba_right = get_permission(account_list[i], follow_partition->mount_point, folder_list[n], "cifs");
595						if (first == 1)
596							first = 0;
597						else
598							fprintf(fp, ", ");
599
600						fprintf(fp, "%s", account_list[i]);
601					}
602					fprintf(fp, "\n");
603
604					fprintf(fp, "invalid users = ");
605					first = 1;
606					for (i = 0; i < acc_num; ++i) {
607						samba_right = get_permission(account_list[i], follow_partition->mount_point, folder_list[n], "cifs");
608						if (samba_right >= 1)
609							continue;
610
611						if (first == 1)
612							first = 0;
613						else
614							fprintf(fp, ", ");
615
616						fprintf(fp, "%s", account_list[i]);
617					}
618					fprintf(fp, "\n");
619
620					fprintf(fp, "read list = ");
621					first = 1;
622					for (i = 0; i < acc_num; ++i) {
623						samba_right = get_permission(account_list[i], follow_partition->mount_point, folder_list[n], "cifs");
624						if (samba_right < 1)
625							continue;
626
627						if (first == 1)
628							first = 0;
629						else
630							fprintf(fp, ", ");
631
632						fprintf(fp, "%s", account_list[i]);
633					}
634					fprintf(fp, "\n");
635
636					fprintf(fp, "write list = ");
637					first = 1;
638					for (i = 0; i < acc_num; ++i) {
639						samba_right = get_permission(account_list[i], follow_partition->mount_point, folder_list[n], "cifs");
640						if (samba_right < 2)
641							continue;
642
643						if (first == 1)
644							first = 0;
645						else
646							fprintf(fp, ", ");
647
648						fprintf(fp, "%s", account_list[i]);
649					}
650					fprintf(fp, "\n");
651				}
652
653				free_2_dimension_list(&sh_num, &folder_list);
654			}
655		}
656
657		free_2_dimension_list(&acc_num, &account_list);
658	}
659
660confpage:
661	if(fp != NULL)
662		fclose(fp);
663	free_disk_data(&disks_info);
664	return 0;
665}
666