1/*
2   Unix SMB/CIFS implementation.
3   string substitution functions
4   Copyright (C) Andrew Tridgell 1992-2000
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2 of the License, or
9   (at your option) any later version.
10
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program; if not, write to the Free Software
18   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19*/
20
21
22#include "includes.h"
23
24fstring local_machine="";
25fstring remote_arch="UNKNOWN";
26userdom_struct current_user_info;
27fstring remote_proto="UNKNOWN";
28
29static fstring remote_machine;
30static fstring smb_user_name;
31
32/**
33 * Set the 'local' machine name
34 * @param local_name the name we are being called
35 * @param if this is the 'final' name for us, not be be changed again
36 */
37
38void set_local_machine_name(const char* local_name, BOOL perm)
39{
40	static BOOL already_perm = False;
41	fstring tmp_local_machine;
42
43	fstrcpy(tmp_local_machine,local_name);
44	trim_char(tmp_local_machine,' ',' ');
45
46	/*
47	 * Windows NT/2k uses "*SMBSERVER" and XP uses "*SMBSERV"
48	 * arrggg!!!
49	 */
50
51	if ( strequal(tmp_local_machine, "*SMBSERVER") || strequal(tmp_local_machine, "*SMBSERV") )  {
52		fstrcpy( local_machine, client_socket_addr() );
53		return;
54	}
55
56	if (already_perm)
57		return;
58
59	already_perm = perm;
60
61	alpha_strcpy(local_machine,tmp_local_machine,SAFE_NETBIOS_CHARS,sizeof(local_machine)-1);
62	strlower_m(local_machine);
63}
64
65/**
66 * Set the 'remote' machine name
67 * @param remote_name the name our client wants to be called by
68 * @param if this is the 'final' name for them, not be be changed again
69 */
70
71void set_remote_machine_name(const char* remote_name, BOOL perm)
72{
73	static BOOL already_perm = False;
74	fstring tmp_remote_machine;
75
76	if (already_perm)
77		return;
78
79	already_perm = perm;
80
81	fstrcpy(tmp_remote_machine,remote_name);
82	trim_char(tmp_remote_machine,' ',' ');
83	alpha_strcpy(remote_machine,tmp_remote_machine,SAFE_NETBIOS_CHARS,sizeof(remote_machine)-1);
84	strlower_m(remote_machine);
85}
86
87const char* get_remote_machine_name(void)
88{
89	return remote_machine;
90}
91
92const char* get_local_machine_name(void)
93{
94	if (!*local_machine) {
95		return global_myname();
96	}
97
98	return local_machine;
99}
100
101/*******************************************************************
102 Setup the string used by %U substitution.
103********************************************************************/
104
105void sub_set_smb_name(const char *name)
106{
107	fstring tmp;
108
109	/* don't let anonymous logins override the name */
110	if (! *name)
111		return;
112
113	fstrcpy(tmp,name);
114	trim_char(tmp,' ',' ');
115	strlower_m(tmp);
116	alpha_strcpy(smb_user_name,tmp,SAFE_NETBIOS_CHARS,sizeof(smb_user_name)-1);
117}
118
119char* sub_get_smb_name( void )
120{
121	return smb_user_name;
122}
123
124/*******************************************************************
125 Setup the strings used by substitutions. Called per packet. Ensure
126 %U name is set correctly also.
127********************************************************************/
128
129void set_current_user_info(const userdom_struct *pcui)
130{
131	current_user_info = *pcui;
132	/* The following is safe as current_user_info.smb_name
133	 * has already been sanitised in register_vuid. */
134	fstrcpy(smb_user_name, current_user_info.smb_name);
135}
136
137/*******************************************************************
138 return the current active user name
139*******************************************************************/
140
141const char* get_current_username( void )
142{
143	if ( current_user_info.smb_name[0] == '\0' )
144		return smb_user_name;
145
146	return current_user_info.smb_name;
147}
148
149/*******************************************************************
150 Given a pointer to a %$(NAME) expand it as an environment variable.
151 Return the number of characters by which the pointer should be advanced.
152 Based on code by Branko Cibej <branko.cibej@hermes.si>
153 When this is called p points at the '%' character.
154********************************************************************/
155
156static size_t expand_env_var(char *p, int len)
157{
158	fstring envname;
159	char *envval;
160	char *q, *r;
161	int copylen;
162
163	if (p[1] != '$')
164		return 1;
165
166	if (p[2] != '(')
167		return 2;
168
169	/*
170	 * Look for the terminating ')'.
171	 */
172
173	if ((q = strchr_m(p,')')) == NULL) {
174		DEBUG(0,("expand_env_var: Unterminated environment variable [%s]\n", p));
175		return 2;
176	}
177
178	/*
179	 * Extract the name from within the %$(NAME) string.
180	 */
181
182	r = p+3;
183	copylen = MIN((q-r),(sizeof(envname)-1));
184	strncpy(envname,r,copylen);
185	envname[copylen] = '\0';
186
187	if ((envval = getenv(envname)) == NULL) {
188		DEBUG(0,("expand_env_var: Environment variable [%s] not set\n", envname));
189		return 2;
190	}
191
192	/*
193	 * Copy the full %$(NAME) into envname so it
194	 * can be replaced.
195	 */
196
197	copylen = MIN((q+1-p),(sizeof(envname)-1));
198	strncpy(envname,p,copylen);
199	envname[copylen] = '\0';
200	string_sub(p,envname,envval,len);
201	return 0; /* Allow the environment contents to be parsed. */
202}
203
204/*******************************************************************
205 Given a pointer to a %$(NAME) in p and the whole string in str
206 expand it as an environment variable.
207 Return a new allocated and expanded string.
208 Based on code by Branko Cibej <branko.cibej@hermes.si>
209 When this is called p points at the '%' character.
210 May substitute multiple occurrencies of the same env var.
211********************************************************************/
212
213
214static char * realloc_expand_env_var(char *str, char *p)
215{
216	char *envname;
217	char *envval;
218	char *q, *r;
219	int copylen;
220
221	if (p[0] != '%' || p[1] != '$' || p[2] != '(')
222		return str;
223
224	/*
225	 * Look for the terminating ')'.
226	 */
227
228	if ((q = strchr_m(p,')')) == NULL) {
229		DEBUG(0,("expand_env_var: Unterminated environment variable [%s]\n", p));
230		return str;
231	}
232
233	/*
234	 * Extract the name from within the %$(NAME) string.
235	 */
236
237	r = p + 3;
238	copylen = q - r;
239	envname = (char *)SMB_MALLOC(copylen + 1 + 4); /* reserve space for use later add %$() chars */
240	if (envname == NULL) return NULL;
241	strncpy(envname,r,copylen);
242	envname[copylen] = '\0';
243
244	if ((envval = getenv(envname)) == NULL) {
245		DEBUG(0,("expand_env_var: Environment variable [%s] not set\n", envname));
246		SAFE_FREE(envname);
247		return str;
248	}
249
250	/*
251	 * Copy the full %$(NAME) into envname so it
252	 * can be replaced.
253	 */
254
255	copylen = q + 1 - p;
256	strncpy(envname,p,copylen);
257	envname[copylen] = '\0';
258	r = realloc_string_sub(str, envname, envval);
259	SAFE_FREE(envname);
260	if (r == NULL) return NULL;
261	return r;
262}
263
264/*******************************************************************
265 Patch from jkf@soton.ac.uk
266 Added this to implement %p (NIS auto-map version of %H)
267*******************************************************************/
268
269static char *automount_path(const char *user_name)
270{
271	static pstring server_path;
272
273	/* use the passwd entry as the default */
274	/* this will be the default if WITH_AUTOMOUNT is not used or fails */
275
276	pstrcpy(server_path, get_user_home_dir(user_name));
277
278#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
279
280	if (lp_nis_home_map()) {
281		char *home_path_start;
282		char *automount_value = automount_lookup(user_name);
283
284		if(strlen(automount_value) > 0) {
285			home_path_start = strchr_m(automount_value,':');
286			if (home_path_start != NULL) {
287				DEBUG(5, ("NIS lookup succeeded.  Home path is: %s\n",
288						home_path_start?(home_path_start+1):""));
289				pstrcpy(server_path, home_path_start+1);
290			}
291		} else {
292			/* NIS key lookup failed: default to user home directory from password file */
293			DEBUG(5, ("NIS lookup failed. Using Home path from passwd file. Home path is: %s\n", server_path ));
294		}
295	}
296#endif
297
298	DEBUG(4,("Home server path: %s\n", server_path));
299
300	return server_path;
301}
302
303/*******************************************************************
304 Patch from jkf@soton.ac.uk
305 This is Luke's original function with the NIS lookup code
306 moved out to a separate function.
307*******************************************************************/
308
309static const char *automount_server(const char *user_name)
310{
311	static pstring server_name;
312	const char *local_machine_name = get_local_machine_name();
313
314	/* use the local machine name as the default */
315	/* this will be the default if WITH_AUTOMOUNT is not used or fails */
316	if (local_machine_name && *local_machine_name)
317		pstrcpy(server_name, local_machine_name);
318	else
319		pstrcpy(server_name, global_myname());
320
321#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
322
323	if (lp_nis_home_map()) {
324	        int home_server_len;
325		char *automount_value = automount_lookup(user_name);
326		home_server_len = strcspn(automount_value,":");
327		DEBUG(5, ("NIS lookup succeeded.  Home server length: %d\n",home_server_len));
328		if (home_server_len > sizeof(pstring))
329			home_server_len = sizeof(pstring);
330		strncpy(server_name, automount_value, home_server_len);
331                server_name[home_server_len] = '\0';
332	}
333#endif
334
335	DEBUG(4,("Home server: %s\n", server_name));
336
337	return server_name;
338}
339
340/****************************************************************************
341 Do some standard substitutions in a string.
342 len is the length in bytes of the space allowed in string str. If zero means
343 don't allow expansions.
344****************************************************************************/
345
346void standard_sub_basic(const char *smb_name, char *str,size_t len)
347{
348	char *p, *s;
349	fstring pidstr;
350	struct passwd *pass;
351	const char *local_machine_name = get_local_machine_name();
352
353	for (s=str; (p=strchr_m(s, '%'));s=p) {
354		fstring tmp_str;
355
356		int l = (int)len - (int)(p-str);
357
358		if (l < 0)
359			l = 0;
360
361		switch (*(p+1)) {
362		case 'U' :
363			fstrcpy(tmp_str, smb_name);
364			strlower_m(tmp_str);
365			string_sub(p,"%U",tmp_str,l);
366			break;
367		case 'G' :
368			fstrcpy(tmp_str, smb_name);
369			if ((pass = Get_Pwnam(tmp_str))!=NULL) {
370				string_sub(p,"%G",gidtoname(pass->pw_gid),l);
371			} else {
372				p += 2;
373			}
374			break;
375		case 'D' :
376			fstrcpy(tmp_str, current_user_info.domain);
377			strupper_m(tmp_str);
378			string_sub(p,"%D", tmp_str,l);
379			break;
380		case 'I' :
381			string_sub(p,"%I", client_addr(),l);
382			break;
383		case 'i' :
384			string_sub(p,"%i", client_socket_addr(),l);
385			break;
386		case 'L' :
387			if (local_machine_name && *local_machine_name)
388				string_sub(p,"%L", local_machine_name,l);
389			else {
390				pstring temp_name;
391
392				pstrcpy(temp_name, global_myname());
393				strlower_m(temp_name);
394				string_sub(p,"%L", temp_name,l);
395			}
396			break;
397		case 'M' :
398			string_sub(p,"%M", client_name(),l);
399			break;
400		case 'R' :
401			string_sub(p,"%R", remote_proto,l);
402			break;
403		case 'T' :
404			string_sub(p,"%T", timestring(False),l);
405			break;
406		case 'a' :
407			string_sub(p,"%a", remote_arch,l);
408			break;
409		case 'd' :
410			slprintf(pidstr,sizeof(pidstr)-1, "%d",(int)sys_getpid());
411			string_sub(p,"%d", pidstr,l);
412			break;
413		case 'h' :
414			string_sub(p,"%h", myhostname(),l);
415			break;
416		case 'm' :
417			string_sub(p,"%m", get_remote_machine_name(),l);
418			break;
419		case 'v' :
420			string_sub(p,"%v", SAMBA_VERSION_STRING,l);
421			break;
422		case '$' :
423			p += expand_env_var(p,l);
424			break; /* Expand environment variables */
425		case '\0':
426			p++;
427			break; /* don't run off the end of the string */
428
429		default: p+=2;
430			break;
431		}
432	}
433}
434
435static void standard_sub_advanced(int snum, const char *user,
436				  const char *connectpath, gid_t gid,
437				  const char *smb_name, char *str, size_t len)
438{
439	char *p, *s, *home;
440
441	for (s=str; (p=strchr_m(s, '%'));s=p) {
442		int l = (int)len - (int)(p-str);
443
444		if (l < 0)
445			l = 0;
446
447		switch (*(p+1)) {
448		case 'N' :
449			string_sub(p,"%N", automount_server(user),l);
450			break;
451		case 'H':
452			if ((home = get_user_home_dir(user)))
453				string_sub(p,"%H",home, l);
454			else
455				p += 2;
456			break;
457		case 'P':
458			string_sub(p,"%P", connectpath, l);
459			break;
460		case 'S':
461			if ( snum != -1 )
462				string_sub(p,"%S", lp_servicename(snum), l);
463			break;
464		case 'g':
465			string_sub(p,"%g", gidtoname(gid), l);
466			break;
467		case 'u':
468			string_sub(p,"%u", user, l);
469			break;
470
471			/* Patch from jkf@soton.ac.uk Left the %N (NIS
472			 * server name) in standard_sub_basic as it is
473			 * a feature for logon servers, hence uses the
474			 * username.  The %p (NIS server path) code is
475			 * here as it is used instead of the default
476			 * "path =" string in [homes] and so needs the
477			 * service name, not the username.  */
478		case 'p':
479			if ( snum != -1 )
480				string_sub(p,"%p", automount_path(lp_servicename(snum)), l);
481			break;
482		case '\0':
483			p++;
484			break; /* don't run off the end of the string */
485
486		default: p+=2;
487			break;
488		}
489	}
490
491	standard_sub_basic(smb_name, str, len);
492}
493
494/****************************************************************************
495 Do some standard substitutions in a string.
496 This function will return an allocated string that have to be freed.
497****************************************************************************/
498
499char *talloc_sub_basic(TALLOC_CTX *mem_ctx, const char *smb_name, const char *str)
500{
501	char *a, *t;
502       	a = alloc_sub_basic(smb_name, str);
503	if (!a) return NULL;
504	t = talloc_strdup(mem_ctx, a);
505	SAFE_FREE(a);
506	return t;
507}
508
509char *alloc_sub_basic(const char *smb_name, const char *str)
510{
511	char *b, *p, *s, *t, *r, *a_string;
512	fstring pidstr;
513	struct passwd *pass;
514	const char *local_machine_name = get_local_machine_name();
515
516	/* workaround to prevent a crash while lookinf at bug #687 */
517
518	if ( !str ) {
519		DEBUG(0,("alloc_sub_basic: NULL source string!  This should not happen\n"));
520		return NULL;
521	}
522
523	a_string = SMB_STRDUP(str);
524	if (a_string == NULL) {
525		DEBUG(0, ("alloc_sub_specified: Out of memory!\n"));
526		return NULL;
527	}
528
529	for (b = s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) {
530
531		r = NULL;
532		b = t = a_string;
533
534		switch (*(p+1)) {
535		case 'U' :
536			r = strdup_lower(smb_name);
537			if (r == NULL) goto error;
538			t = realloc_string_sub(t, "%U", r);
539			break;
540		case 'G' :
541			r = SMB_STRDUP(smb_name);
542			if (r == NULL) goto error;
543			if ((pass = Get_Pwnam(r))!=NULL) {
544				t = realloc_string_sub(t, "%G", gidtoname(pass->pw_gid));
545			}
546			break;
547		case 'D' :
548			r = strdup_upper(current_user_info.domain);
549			if (r == NULL) goto error;
550			t = realloc_string_sub(t, "%D", r);
551			break;
552		case 'I' :
553			t = realloc_string_sub(t, "%I", client_addr());
554			break;
555		case 'L' :
556			if (local_machine_name && *local_machine_name)
557				t = realloc_string_sub(t, "%L", local_machine_name);
558			else
559				t = realloc_string_sub(t, "%L", global_myname());
560			break;
561		case 'N':
562			t = realloc_string_sub(t, "%N", automount_server(smb_name));
563			break;
564		case 'M' :
565			t = realloc_string_sub(t, "%M", client_name());
566			break;
567		case 'R' :
568			t = realloc_string_sub(t, "%R", remote_proto);
569			break;
570		case 'T' :
571			t = realloc_string_sub(t, "%T", timestring(False));
572			break;
573		case 'a' :
574			t = realloc_string_sub(t, "%a", remote_arch);
575			break;
576		case 'd' :
577			slprintf(pidstr,sizeof(pidstr)-1, "%d",(int)sys_getpid());
578			t = realloc_string_sub(t, "%d", pidstr);
579			break;
580		case 'h' :
581			t = realloc_string_sub(t, "%h", myhostname());
582			break;
583		case 'm' :
584			t = realloc_string_sub(t, "%m", remote_machine);
585			break;
586		case 'v' :
587			t = realloc_string_sub(t, "%v", SAMBA_VERSION_STRING);
588			break;
589		case '$' :
590			t = realloc_expand_env_var(t, p); /* Expand environment variables */
591			break;
592
593		default:
594			break;
595		}
596
597		p++;
598		SAFE_FREE(r);
599		if (t == NULL) goto error;
600		a_string = t;
601	}
602
603	return a_string;
604error:
605	SAFE_FREE(a_string);
606	return NULL;
607}
608
609/****************************************************************************
610 Do some specific substitutions in a string.
611 This function will return an allocated string that have to be freed.
612****************************************************************************/
613
614char *talloc_sub_specified(TALLOC_CTX *mem_ctx,
615			const char *input_string,
616			const char *username,
617			const char *domain,
618			uid_t uid,
619			gid_t gid)
620{
621	char *a, *t;
622       	a = alloc_sub_specified(input_string, username, domain, uid, gid);
623	if (!a) return NULL;
624	t = talloc_strdup(mem_ctx, a);
625	SAFE_FREE(a);
626	return t;
627}
628
629char *alloc_sub_specified(const char *input_string,
630			const char *username,
631			const char *domain,
632			uid_t uid,
633			gid_t gid)
634{
635	char *a_string, *ret_string;
636	char *b, *p, *s, *t;
637
638	a_string = SMB_STRDUP(input_string);
639	if (a_string == NULL) {
640		DEBUG(0, ("alloc_sub_specified: Out of memory!\n"));
641		return NULL;
642	}
643
644	for (b = s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) {
645
646		b = t = a_string;
647
648		switch (*(p+1)) {
649		case 'U' :
650			t = realloc_string_sub(t, "%U", username);
651			break;
652		case 'u' :
653			t = realloc_string_sub(t, "%u", username);
654			break;
655		case 'G' :
656			if (gid != -1) {
657				t = realloc_string_sub(t, "%G", gidtoname(gid));
658			} else {
659				t = realloc_string_sub(t, "%G", "NO_GROUP");
660			}
661			break;
662		case 'g' :
663			if (gid != -1) {
664				t = realloc_string_sub(t, "%g", gidtoname(gid));
665			} else {
666				t = realloc_string_sub(t, "%g", "NO_GROUP");
667			}
668			break;
669		case 'D' :
670			t = realloc_string_sub(t, "%D", domain);
671			break;
672		case 'N' :
673			t = realloc_string_sub(t, "%N", automount_server(username));
674			break;
675		default:
676			break;
677		}
678
679		p++;
680		if (t == NULL) {
681			SAFE_FREE(a_string);
682			return NULL;
683		}
684		a_string = t;
685	}
686
687	ret_string = alloc_sub_basic(username, a_string);
688	SAFE_FREE(a_string);
689	return ret_string;
690}
691
692char *talloc_sub_advanced(TALLOC_CTX *mem_ctx,
693			int snum,
694			const char *user,
695			const char *connectpath,
696			gid_t gid,
697			const char *smb_name,
698			const char *str)
699{
700	char *a, *t;
701       	a = alloc_sub_advanced(snum, user, connectpath, gid, smb_name, str);
702	if (!a) return NULL;
703	t = talloc_strdup(mem_ctx, a);
704	SAFE_FREE(a);
705	return t;
706}
707
708char *alloc_sub_advanced(int snum, const char *user,
709				  const char *connectpath, gid_t gid,
710				  const char *smb_name, const char *str)
711{
712	char *a_string, *ret_string;
713	char *b, *p, *s, *t, *h;
714
715	a_string = SMB_STRDUP(str);
716	if (a_string == NULL) {
717		DEBUG(0, ("alloc_sub_specified: Out of memory!\n"));
718		return NULL;
719	}
720
721	for (b = s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) {
722
723		b = t = a_string;
724
725		switch (*(p+1)) {
726		case 'N' :
727			t = realloc_string_sub(t, "%N", automount_server(user));
728			break;
729		case 'H':
730			if ((h = get_user_home_dir(user)))
731				t = realloc_string_sub(t, "%H", h);
732			break;
733		case 'P':
734			t = realloc_string_sub(t, "%P", connectpath);
735			break;
736		case 'S':
737			t = realloc_string_sub(t, "%S", lp_servicename(snum));
738			break;
739		case 'g':
740			t = realloc_string_sub(t, "%g", gidtoname(gid));
741			break;
742		case 'u':
743			t = realloc_string_sub(t, "%u", user);
744			break;
745
746			/* Patch from jkf@soton.ac.uk Left the %N (NIS
747			 * server name) in standard_sub_basic as it is
748			 * a feature for logon servers, hence uses the
749			 * username.  The %p (NIS server path) code is
750			 * here as it is used instead of the default
751			 * "path =" string in [homes] and so needs the
752			 * service name, not the username.  */
753		case 'p':
754			t = realloc_string_sub(t, "%p", automount_path(lp_servicename(snum)));
755			break;
756
757		default:
758			break;
759		}
760
761		p++;
762		if (t == NULL) {
763			SAFE_FREE(a_string);
764			return NULL;
765		}
766		a_string = t;
767	}
768
769	ret_string = alloc_sub_basic(smb_name, a_string);
770	SAFE_FREE(a_string);
771	return ret_string;
772}
773
774/****************************************************************************
775 Do some standard substitutions in a string.
776****************************************************************************/
777
778void standard_sub_conn(connection_struct *conn, char *str, size_t len)
779{
780	standard_sub_advanced(SNUM(conn), conn->user, conn->connectpath,
781			conn->gid, smb_user_name, str, len);
782}
783
784char *talloc_sub_conn(TALLOC_CTX *mem_ctx, connection_struct *conn, const char *str)
785{
786	return talloc_sub_advanced(mem_ctx, SNUM(conn), conn->user,
787			conn->connectpath, conn->gid,
788			smb_user_name, str);
789}
790
791char *alloc_sub_conn(connection_struct *conn, const char *str)
792{
793	return alloc_sub_advanced(SNUM(conn), conn->user, conn->connectpath,
794			conn->gid, smb_user_name, str);
795}
796
797/****************************************************************************
798 Like standard_sub but by snum.
799****************************************************************************/
800
801void standard_sub_snum(int snum, char *str, size_t len)
802{
803	extern struct current_user current_user;
804	static uid_t cached_uid = -1;
805	static fstring cached_user;
806	/* calling uidtoname() on every substitute would be too expensive, so
807	   we cache the result here as nearly every call is for the same uid */
808
809	if (cached_uid != current_user.uid) {
810		fstrcpy(cached_user, uidtoname(current_user.uid));
811		cached_uid = current_user.uid;
812	}
813
814	standard_sub_advanced(snum, cached_user, "", current_user.gid,
815			      smb_user_name, str, len);
816}
817