2 Unix SMB/CIFS implementation.
3 string substitution functions
4 Copyright (C) Andrew Tridgell 1992-2000
5 Copyright (C) Gerald Carter 2006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "system/passwd.h"
27 /* Max DNS name is 253 + '\0' */
28 #define MACHINE_NAME_SIZE 254
30 static char local_machine
[MACHINE_NAME_SIZE
];
31 static char remote_machine
[MACHINE_NAME_SIZE
];
33 userdom_struct current_user_info
;
34 fstring remote_proto
="UNKNOWN";
37 * Set the 'local' machine name
38 * @param local_name the name we are being called
39 * @param if this is the 'final' name for us, not be be changed again
41 bool set_local_machine_name(const char *local_name
, bool perm
)
43 static bool already_perm
= false;
44 char tmp
[MACHINE_NAME_SIZE
];
50 strlcpy(tmp
, local_name
, sizeof(tmp
));
51 trim_char(tmp
, ' ', ' ');
53 alpha_strcpy(local_machine
,
56 sizeof(local_machine
) - 1);
57 if (!strlower_m(local_machine
)) {
66 const char *get_local_machine_name(void)
68 if (local_machine
[0] == '\0') {
69 return lp_netbios_name();
76 * Set the 'remote' machine name
78 * @param remote_name the name our client wants to be called by
79 * @param if this is the 'final' name for them, not be be changed again
81 bool set_remote_machine_name(const char *remote_name
, bool perm
)
83 static bool already_perm
= False
;
84 char tmp
[MACHINE_NAME_SIZE
];
90 strlcpy(tmp
, remote_name
, sizeof(tmp
));
91 trim_char(tmp
, ' ', ' ');
93 alpha_strcpy(remote_machine
,
96 sizeof(remote_machine
) - 1);
97 if (!strlower_m(remote_machine
)) {
106 const char *get_remote_machine_name(void)
108 return remote_machine
;
111 static char sub_peeraddr
[INET6_ADDRSTRLEN
];
112 static const char *sub_peername
= NULL
;
113 static char sub_sockaddr
[INET6_ADDRSTRLEN
];
115 void sub_set_socket_ids(const char *peeraddr
, const char *peername
,
116 const char *sockaddr
)
118 const char *addr
= peeraddr
;
120 if (strnequal(addr
, "::ffff:", 7)) {
123 strlcpy(sub_peeraddr
, addr
, sizeof(sub_peeraddr
));
125 if (sub_peername
!= NULL
&&
126 sub_peername
!= sub_peeraddr
) {
127 talloc_free(discard_const_p(char,sub_peername
));
130 sub_peername
= talloc_strdup(NULL
, peername
);
131 if (sub_peername
== NULL
) {
132 sub_peername
= sub_peeraddr
;
136 * Shouldn't we do the ::ffff: cancellation here as well? The
137 * original code in talloc_sub_basic() did not do it, so I'm
138 * leaving it out here as well for compatibility.
140 strlcpy(sub_sockaddr
, sockaddr
, sizeof(sub_sockaddr
));
143 /*******************************************************************
144 Setup the strings used by substitutions. Called per packet. Ensure
145 %U name is set correctly also.
147 smb_name must be sanitized by alpha_strcpy
148 ********************************************************************/
150 void set_current_user_info(const char *smb_name
, const char *unix_name
,
153 static const void *last_smb_name
;
154 static const void *last_unix_name
;
155 static const void *last_domain
;
157 if (likely(last_smb_name
== smb_name
&&
158 last_unix_name
== unix_name
&&
159 last_domain
== domain
))
164 fstrcpy(current_user_info
.smb_name
, smb_name
);
165 fstrcpy(current_user_info
.unix_name
, unix_name
);
166 fstrcpy(current_user_info
.domain
, domain
);
168 last_smb_name
= smb_name
;
169 last_unix_name
= unix_name
;
170 last_domain
= domain
;
173 /*******************************************************************
174 Return the current active user name.
175 *******************************************************************/
177 const char *get_current_username(void)
179 return current_user_info
.smb_name
;
182 /*******************************************************************
183 Given a pointer to a %$(NAME) in p and the whole string in str
184 expand it as an environment variable.
185 str must be a talloced string.
186 Return a new allocated and expanded string.
187 Based on code by Branko Cibej <branko.cibej@hermes.si>
188 When this is called p points at the '%' character.
189 May substitute multiple occurrencies of the same env var.
190 ********************************************************************/
192 static char *realloc_expand_env_var(char *str
, char *p
)
199 if (p
[0] != '%' || p
[1] != '$' || p
[2] != '(') {
204 * Look for the terminating ')'.
207 if ((q
= strchr_m(p
,')')) == NULL
) {
208 DEBUG(0,("expand_env_var: Unterminated environment variable [%s]\n", p
));
213 * Extract the name from within the %$(NAME) string.
219 /* reserve space for use later add %$() chars */
220 if ( (envname
= talloc_array(talloc_tos(), char, copylen
+ 1 + 4)) == NULL
) {
224 strncpy(envname
,r
,copylen
);
225 envname
[copylen
] = '\0';
227 if ((envval
= getenv(envname
)) == NULL
) {
228 DEBUG(0,("expand_env_var: Environment variable [%s] not set\n", envname
));
229 TALLOC_FREE(envname
);
234 * Copy the full %$(NAME) into envname so it
239 strncpy(envname
,p
,copylen
);
240 envname
[copylen
] = '\0';
241 r
= realloc_string_sub(str
, envname
, envval
);
242 TALLOC_FREE(envname
);
247 /*******************************************************************
248 Patch from jkf@soton.ac.uk
249 Added this to implement %p (NIS auto-map version of %H)
250 *******************************************************************/
252 static const char *automount_path(const char *user_name
)
254 TALLOC_CTX
*ctx
= talloc_tos();
255 const char *server_path
;
257 /* use the passwd entry as the default */
258 /* this will be the default if WITH_AUTOMOUNT is not used or fails */
260 server_path
= talloc_strdup(ctx
, get_user_home_dir(ctx
, user_name
));
265 #if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
267 if (lp_nis_homedir()) {
268 const char *home_path_start
;
269 char *automount_value
= automount_lookup(ctx
, user_name
);
271 if(automount_value
&& strlen(automount_value
) > 0) {
272 home_path_start
= strchr_m(automount_value
,':');
273 if (home_path_start
!= NULL
) {
274 DEBUG(5, ("NIS lookup succeeded. "
275 "Home path is: %s\n",
277 (home_path_start
+1):""));
278 server_path
= talloc_strdup(ctx
,
285 /* NIS key lookup failed: default to
286 * user home directory from password file */
287 DEBUG(5, ("NIS lookup failed. Using Home path from "
288 "passwd file. Home path is: %s\n", server_path
));
293 DEBUG(4,("Home server path: %s\n", server_path
));
297 /*******************************************************************
298 Patch from jkf@soton.ac.uk
299 This is Luke's original function with the NIS lookup code
300 moved out to a separate function.
301 *******************************************************************/
303 static const char *automount_server(const char *user_name
)
305 TALLOC_CTX
*ctx
= talloc_tos();
306 const char *server_name
;
307 const char *local_machine_name
= get_local_machine_name();
309 /* use the local machine name as the default */
310 /* this will be the default if WITH_AUTOMOUNT is not used or fails */
311 if (local_machine_name
&& *local_machine_name
) {
312 server_name
= talloc_strdup(ctx
, local_machine_name
);
314 server_name
= talloc_strdup(ctx
, lp_netbios_name());
321 #if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
322 if (lp_nis_homedir()) {
325 char *automount_value
= automount_lookup(ctx
, user_name
);
326 if (!automount_value
) {
329 srv
= talloc_strdup(ctx
, automount_value
);
333 p
= strchr_m(srv
, ':');
339 DEBUG(5, ("NIS lookup succeeded. Home server %s\n",
344 DEBUG(4,("Home server: %s\n", server_name
));
348 /****************************************************************************
349 Do some standard substitutions in a string.
350 len is the length in bytes of the space allowed in string str. If zero means
351 don't allow expansions.
352 ****************************************************************************/
354 void standard_sub_basic(const char *smb_name
, const char *domain_name
,
355 char *str
, size_t len
)
359 if ( (s
= talloc_sub_basic(talloc_tos(), smb_name
, domain_name
, str
)) != NULL
) {
360 strncpy( str
, s
, len
);
367 * Limit addresses to hexalpha charactes and underscore, safe for path
368 * components for Windows clients.
370 static void make_address_pathsafe(char *addr
)
372 while(addr
&& *addr
) {
373 if(!isxdigit(*addr
)) {
380 /****************************************************************************
381 Do some standard substitutions in a string.
382 This function will return a talloced string that has to be freed.
383 ****************************************************************************/
385 char *talloc_sub_basic(TALLOC_CTX
*mem_ctx
,
386 const char *smb_name
,
387 const char *domain_name
,
390 char *b
, *p
, *s
, *r
, *a_string
;
391 fstring pidstr
, vnnstr
;
392 const char *local_machine_name
= get_local_machine_name();
393 TALLOC_CTX
*tmp_ctx
= NULL
;
395 /* workaround to prevent a crash while looking at bug #687 */
398 DEBUG(0,("talloc_sub_basic: NULL source string! This should not happen\n"));
402 a_string
= talloc_strdup(mem_ctx
, str
);
403 if (a_string
== NULL
) {
404 DEBUG(0, ("talloc_sub_basic: Out of memory!\n"));
408 tmp_ctx
= talloc_stackframe();
410 for (s
= a_string
; (p
= strchr_m(s
, '%')); s
= a_string
+ (p
- b
)) {
417 r
= strlower_talloc(tmp_ctx
, smb_name
);
421 a_string
= realloc_string_sub(a_string
, "%U", r
);
425 bool is_domain_name
= false;
426 const char *sep
= lp_winbind_separator();
428 if (domain_name
!= NULL
&& domain_name
[0] != '\0' &&
429 (lp_security() == SEC_ADS
||
430 lp_security() == SEC_DOMAIN
)) {
431 r
= talloc_asprintf(tmp_ctx
,
436 is_domain_name
= true;
438 r
= talloc_strdup(tmp_ctx
, smb_name
);
444 pass
= Get_Pwnam_alloc(tmp_ctx
, r
);
448 group_name
= gidtoname(pass
->pw_gid
);
449 if (is_domain_name
) {
451 group_sep
= strchr_m(group_name
, *sep
);
452 if (group_sep
!= NULL
) {
453 group_name
= group_sep
+ 1;
456 a_string
= realloc_string_sub(a_string
,
464 r
= strupper_talloc(tmp_ctx
, domain_name
);
468 a_string
= realloc_string_sub(a_string
, "%D", r
);
471 a_string
= realloc_string_sub(
473 sub_peeraddr
[0] ? sub_peeraddr
: "0.0.0.0");
477 r
= talloc_strdup(tmp_ctx
,
478 sub_peeraddr
[0] ? sub_peeraddr
: "0.0.0.0");
479 make_address_pathsafe(r
);
480 a_string
= realloc_string_sub(a_string
, "%J", r
);
484 a_string
= realloc_string_sub(
486 sub_sockaddr
[0] ? sub_sockaddr
: "0.0.0.0");
489 r
= talloc_strdup(tmp_ctx
,
490 sub_sockaddr
[0] ? sub_sockaddr
: "0.0.0.0");
491 make_address_pathsafe(r
);
492 a_string
= realloc_string_sub(a_string
, "%j", r
);
496 if ( strncasecmp_m(p
, "%LOGONSERVER%", strlen("%LOGONSERVER%")) == 0 ) {
499 if (local_machine_name
&& *local_machine_name
) {
500 a_string
= realloc_string_sub(a_string
, "%L", local_machine_name
);
502 a_string
= realloc_string_sub(a_string
, "%L", lp_netbios_name());
506 a_string
= realloc_string_sub(a_string
, "%N", automount_server(smb_name
));
509 a_string
= realloc_string_sub(a_string
, "%M",
510 sub_peername
? sub_peername
: "");
513 a_string
= realloc_string_sub(a_string
, "%R", remote_proto
);
516 a_string
= realloc_string_sub(a_string
, "%T", current_timestring(tmp_ctx
, False
));
519 a_string
= realloc_string_sub(a_string
, "%t",
520 current_minimal_timestring(tmp_ctx
, False
));
523 a_string
= realloc_string_sub(a_string
, "%a",
524 get_remote_arch_str());
527 slprintf(pidstr
,sizeof(pidstr
)-1, "%d",(int)getpid());
528 a_string
= realloc_string_sub(a_string
, "%d", pidstr
);
531 a_string
= realloc_string_sub(a_string
, "%h", myhostname());
534 a_string
= realloc_string_sub(a_string
, "%m",
538 a_string
= realloc_string_sub(a_string
, "%v", samba_version_string());
541 a_string
= realloc_string_sub(a_string
, "%w", lp_winbind_separator());
544 a_string
= realloc_expand_env_var(a_string
, p
); /* Expand environment variables */
547 slprintf(vnnstr
,sizeof(vnnstr
)-1, "%u", get_my_vnn());
548 a_string
= realloc_string_sub(a_string
, "%V", vnnstr
);
557 if (a_string
== NULL
) {
565 TALLOC_FREE(a_string
);
568 TALLOC_FREE(tmp_ctx
);
572 /****************************************************************************
573 Do some specific substitutions in a string.
574 This function will return an allocated string that have to be freed.
575 ****************************************************************************/
577 char *talloc_sub_specified(TALLOC_CTX
*mem_ctx
,
578 const char *input_string
,
579 const char *username
,
586 char *ret_string
= NULL
;
590 if (!(tmp_ctx
= talloc_new(mem_ctx
))) {
591 DEBUG(0, ("talloc_new failed\n"));
595 a_string
= talloc_strdup(tmp_ctx
, input_string
);
596 if (a_string
== NULL
) {
597 DEBUG(0, ("talloc_sub_specified: Out of memory!\n"));
601 for (s
= a_string
; (p
= strchr_m(s
, '%')); s
= a_string
+ (p
- b
)) {
607 a_string
= talloc_string_sub(
608 tmp_ctx
, a_string
, "%U", username
);
611 a_string
= talloc_string_sub(
612 tmp_ctx
, a_string
, "%u", username
);
618 if (grpname
!= NULL
) {
621 name
= gidtoname(gid
);
624 a_string
= talloc_string_sub(tmp_ctx
,
629 a_string
= talloc_string_sub(
638 if (grpname
!= NULL
) {
641 name
= gidtoname(gid
);
644 a_string
= talloc_string_sub(tmp_ctx
,
649 a_string
= talloc_string_sub(
650 tmp_ctx
, a_string
, "%g", "NO_GROUP");
654 a_string
= talloc_string_sub(tmp_ctx
, a_string
,
658 a_string
= talloc_string_sub(
659 tmp_ctx
, a_string
, "%N",
660 automount_server(username
));
667 if (a_string
== NULL
) {
672 /* Watch out, using "mem_ctx" here, so all intermediate stuff goes
673 * away with the TALLOC_FREE(tmp_ctx) further down. */
675 ret_string
= talloc_sub_basic(mem_ctx
, username
, domain
, a_string
);
678 TALLOC_FREE(tmp_ctx
);
682 /****************************************************************************
683 ****************************************************************************/
685 char *talloc_sub_advanced(TALLOC_CTX
*ctx
,
686 const char *servicename
,
688 const char *connectpath
,
695 a_string
= talloc_strdup(talloc_tos(), str
);
696 if (a_string
== NULL
) {
697 DEBUG(0, ("talloc_sub_advanced_only: Out of memory!\n"));
701 for (s
= a_string
; (p
= strchr_m(s
, '%')); s
= a_string
+ (p
- b
)) {
707 a_string
= realloc_string_sub(a_string
, "%N", automount_server(user
));
711 if ((h
= get_user_home_dir(talloc_tos(), user
)))
712 a_string
= realloc_string_sub(a_string
, "%H", h
);
717 a_string
= realloc_string_sub(a_string
, "%P", connectpath
);
720 a_string
= realloc_string_sub(a_string
, "%S", servicename
);
723 a_string
= realloc_string_sub(a_string
, "%g", gidtoname(gid
));
726 a_string
= realloc_string_sub(a_string
, "%u", user
);
729 /* Patch from jkf@soton.ac.uk Left the %N (NIS
730 * server name) in standard_sub_basic as it is
731 * a feature for logon servers, hence uses the
732 * username. The %p (NIS server path) code is
733 * here as it is used instead of the default
734 * "path =" string in [homes] and so needs the
735 * service name, not the username. */
737 a_string
= realloc_string_sub(a_string
, "%p",
738 automount_path(servicename
));
746 if (a_string
== NULL
) {
754 char *talloc_sub_full(TALLOC_CTX
*ctx
,
755 const char *servicename
,
757 const char *connectpath
,
759 const char *smb_name
,
760 const char *domain_name
,
763 char *a_string
, *ret_string
;
765 a_string
= talloc_sub_advanced(ctx
, servicename
, user
, connectpath
,
767 if (a_string
== NULL
) {
771 ret_string
= talloc_sub_basic(ctx
, smb_name
, domain_name
, a_string
);
772 TALLOC_FREE(a_string
);