2 Unix SMB/CIFS implementation.
3 string substitution functions
4 Copyright (C) Andrew Tridgell 1992-2000
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.
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.
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.
24 fstring local_machine="";
25 fstring remote_arch="UNKNOWN";
26 userdom_struct current_user_info;
27 fstring remote_proto="UNKNOWN";
28 fstring remote_machine="";
29 extern pstring global_myname;
31 /*******************************************************************
32 Given a pointer to a %$(NAME) expand it as an environment variable.
33 Return the number of characters by which the pointer should be advanced.
34 Based on code by Branko Cibej <branko.cibej@hermes.si>
35 When this is called p points at the '%' character.
36 ********************************************************************/
38 static size_t expand_env_var(char *p, int len)
52 * Look for the terminating ')'.
55 if ((q = strchr_m(p,')')) == NULL) {
56 DEBUG(0,("expand_env_var: Unterminated environment variable [%s]\n", p));
61 * Extract the name from within the %$(NAME) string.
65 copylen = MIN((q-r),(sizeof(envname)-1));
66 strncpy(envname,r,copylen);
67 envname[copylen] = '\0';
69 if ((envval = getenv(envname)) == NULL) {
70 DEBUG(0,("expand_env_var: Environment variable [%s] not set\n", envname));
75 * Copy the full %$(NAME) into envname so it
79 copylen = MIN((q+1-p),(sizeof(envname)-1));
80 strncpy(envname,p,copylen);
81 envname[copylen] = '\0';
82 string_sub(p,envname,envval,len);
83 return 0; /* Allow the environment contents to be parsed. */
86 /*******************************************************************
87 Given a pointer to a %$(NAME) in p and the whole string in str
88 expand it as an environment variable.
89 Return a new allocated and expanded string.
90 Based on code by Branko Cibej <branko.cibej@hermes.si>
91 When this is called p points at the '%' character.
92 May substitute multiple occurrencies of the same env var.
93 ********************************************************************/
96 static char * realloc_expand_env_var(char *str, char *p)
103 if (p[0] != '%' || p[1] != '$' || p[2] != '(')
107 * Look for the terminating ')'.
110 if ((q = strchr_m(p,')')) == NULL) {
111 DEBUG(0,("expand_env_var: Unterminated environment variable [%s]\n", p));
116 * Extract the name from within the %$(NAME) string.
121 envname = (char *)malloc(copylen + 1 + 4); /* reserve space for use later add %$() chars */
122 if (envname == NULL) return NULL;
123 strncpy(envname,r,copylen);
124 envname[copylen] = '\0';
126 if ((envval = getenv(envname)) == NULL) {
127 DEBUG(0,("expand_env_var: Environment variable [%s] not set\n", envname));
133 * Copy the full %$(NAME) into envname so it
138 strncpy(envname,p,copylen);
139 envname[copylen] = '\0';
140 r = realloc_string_sub(str, envname, envval);
142 if (r == NULL) return NULL;
146 /*******************************************************************
147 Patch from jkf@soton.ac.uk
148 Added this to implement %p (NIS auto-map version of %H)
149 *******************************************************************/
151 static char *automount_path(const char *user_name)
153 static pstring server_path;
155 /* use the passwd entry as the default */
156 /* this will be the default if WITH_AUTOMOUNT is not used or fails */
158 pstrcpy(server_path, get_user_home_dir(user_name));
160 #if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
162 if (lp_nis_home_map()) {
163 char *home_path_start;
164 char *automount_value = automount_lookup(user_name);
166 if(strlen(automount_value) > 0) {
167 home_path_start = strchr_m(automount_value,':');
168 if (home_path_start != NULL) {
169 DEBUG(5, ("NIS lookup succeeded. Home path is: %s\n",
170 home_path_start?(home_path_start+1):""));
171 pstrcpy(server_path, home_path_start+1);
174 /* NIS key lookup failed: default to user home directory from password file */
175 DEBUG(5, ("NIS lookup failed. Using Home path from passwd file. Home path is: %s\n", server_path ));
180 DEBUG(4,("Home server path: %s\n", server_path));
185 /*******************************************************************
186 Patch from jkf@soton.ac.uk
187 This is Luke's original function with the NIS lookup code
188 moved out to a separate function.
189 *******************************************************************/
191 static char *automount_server(const char *user_name)
193 static pstring server_name;
195 /* use the local machine name as the default */
196 /* this will be the default if WITH_AUTOMOUNT is not used or fails */
198 pstrcpy(server_name, local_machine);
200 pstrcpy(server_name, global_myname);
202 #if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
204 if (lp_nis_home_map()) {
206 char *automount_value = automount_lookup(user_name);
207 home_server_len = strcspn(automount_value,":");
208 DEBUG(5, ("NIS lookup succeeded. Home server length: %d\n",home_server_len));
209 if (home_server_len > sizeof(pstring))
210 home_server_len = sizeof(pstring);
211 strncpy(server_name, automount_value, home_server_len);
212 server_name[home_server_len] = '\0';
216 DEBUG(4,("Home server: %s\n", server_name));
221 /****************************************************************************
222 Do some standard substitutions in a string.
223 len is the length in bytes of the space allowed in string str. If zero means
224 don't allow expansions.
225 ****************************************************************************/
227 void standard_sub_basic(const char *smb_name, char *str,size_t len)
233 for (s=str; (p=strchr_m(s, '%'));s=p) {
236 int l = (int)len - (int)(p-str);
243 fstrcpy(tmp_str, smb_name);
245 string_sub(p,"%U",tmp_str,l);
248 fstrcpy(tmp_str, smb_name);
249 if ((pass = Get_Pwnam(tmp_str))!=NULL) {
250 string_sub(p,"%G",gidtoname(pass->pw_gid),l);
256 fstrcpy(tmp_str, current_user_info.domain);
258 string_sub(p,"%D", tmp_str,l);
261 string_sub(p,"%I", client_addr(),l);
265 string_sub(p,"%L", local_machine,l);
267 string_sub(p,"%L", global_myname,l);
270 string_sub(p,"%M", client_name(),l);
273 string_sub(p,"%R", remote_proto,l);
276 string_sub(p,"%T", timestring(False),l);
279 string_sub(p,"%a", remote_arch,l);
282 slprintf(pidstr,sizeof(pidstr)-1, "%d",(int)sys_getpid());
283 string_sub(p,"%d", pidstr,l);
286 string_sub(p,"%h", myhostname(),l);
289 string_sub(p,"%m", remote_machine,l);
292 string_sub(p,"%v", VERSION,l);
295 p += expand_env_var(p,l);
296 break; /* Expand environment variables */
299 break; /* don't run off the end of the string */
307 static void standard_sub_advanced(int snum, const char *user,
308 const char *connectpath, gid_t gid,
309 const char *smb_name, char *str, size_t len)
313 for (s=str; (p=strchr_m(s, '%'));s=p) {
314 int l = (int)len - (int)(p-str);
321 string_sub(p,"%N", automount_server(user),l);
324 if ((home = get_user_home_dir(user)))
325 string_sub(p,"%H",home, l);
330 string_sub(p,"%P", connectpath, l);
333 string_sub(p,"%S", lp_servicename(snum), l);
336 string_sub(p,"%g", gidtoname(gid), l);
339 string_sub(p,"%u", user, l);
342 /* Patch from jkf@soton.ac.uk Left the %N (NIS
343 * server name) in standard_sub_basic as it is
344 * a feature for logon servers, hence uses the
345 * username. The %p (NIS server path) code is
346 * here as it is used instead of the default
347 * "path =" string in [homes] and so needs the
348 * service name, not the username. */
350 string_sub(p,"%p", automount_path(lp_servicename(snum)), l);
354 break; /* don't run off the end of the string */
361 standard_sub_basic(smb_name, str, len);
364 /****************************************************************************
365 Do some standard substitutions in a string.
366 This function will return an allocated string that have to be freed.
367 ****************************************************************************/
369 char *talloc_sub_basic(TALLOC_CTX *mem_ctx, const char *smb_name, const char *str)
372 a = alloc_sub_basic(smb_name, str);
374 t = talloc_strdup(mem_ctx, a);
379 char *alloc_sub_basic(const char *smb_name, const char *str)
381 char *b, *p, *s, *t, *r, *a_string;
385 a_string = strdup(str);
386 if (a_string == NULL) {
387 DEBUG(0, ("alloc_sub_specified: Out of memory!\n"));
391 for (b = s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) {
398 r = strdup_lower(smb_name);
399 if (r == NULL) goto error;
400 t = realloc_string_sub(t, "%U", r);
403 r = strdup(smb_name);
404 if (r == NULL) goto error;
405 if ((pass = Get_Pwnam(r))!=NULL) {
406 t = realloc_string_sub(t, "%G", gidtoname(pass->pw_gid));
410 r = strdup_upper(current_user_info.domain);
411 if (r == NULL) goto error;
412 t = realloc_string_sub(t, "%D", r);
415 t = realloc_string_sub(t, "%I", client_addr());
419 t = realloc_string_sub(t, "%L", local_machine);
421 t = realloc_string_sub(t, "%L", global_myname);
424 t = realloc_string_sub(t, "%M", client_name());
427 t = realloc_string_sub(t, "%R", remote_proto);
430 t = realloc_string_sub(t, "%T", timestring(False));
433 t = realloc_string_sub(t, "%a", remote_arch);
436 slprintf(pidstr,sizeof(pidstr)-1, "%d",(int)sys_getpid());
437 t = realloc_string_sub(t, "%d", pidstr);
440 t = realloc_string_sub(t, "%h", myhostname());
443 t = realloc_string_sub(t, "%m", remote_machine);
446 t = realloc_string_sub(t, "%v", VERSION);
449 t = realloc_expand_env_var(t, p); /* Expand environment variables */
458 if (t == NULL) goto error;
468 /****************************************************************************
469 Do some specific substitutions in a string.
470 This function will return an allocated string that have to be freed.
471 ****************************************************************************/
473 char *talloc_sub_specified(TALLOC_CTX *mem_ctx,
474 const char *input_string,
475 const char *username,
481 a = alloc_sub_specified(input_string, username, domain, uid, gid);
483 t = talloc_strdup(mem_ctx, a);
488 char *alloc_sub_specified(const char *input_string,
489 const char *username,
494 char *a_string, *ret_string;
497 a_string = strdup(input_string);
498 if (a_string == NULL) {
499 DEBUG(0, ("alloc_sub_specified: Out of memory!\n"));
503 for (b = s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) {
509 t = realloc_string_sub(t, "%U", username);
512 t = realloc_string_sub(t, "%u", username);
516 t = realloc_string_sub(t, "%G", gidtoname(gid));
518 t = realloc_string_sub(t, "%G", "NO_GROUP");
523 t = realloc_string_sub(t, "%g", gidtoname(gid));
525 t = realloc_string_sub(t, "%g", "NO_GROUP");
529 t = realloc_string_sub(t, "%D", domain);
532 t = realloc_string_sub(t, "%N", automount_server(username));
546 ret_string = alloc_sub_basic(username, a_string);
551 char *talloc_sub_advanced(TALLOC_CTX *mem_ctx,
554 const char *connectpath,
556 const char *smb_name,
560 a = alloc_sub_advanced(snum, user, connectpath, gid, smb_name, str);
562 t = talloc_strdup(mem_ctx, a);
567 char *alloc_sub_advanced(int snum, const char *user,
568 const char *connectpath, gid_t gid,
569 const char *smb_name, char *str)
571 char *a_string, *ret_string;
572 char *b, *p, *s, *t, *h;
574 a_string = strdup(str);
575 if (a_string == NULL) {
576 DEBUG(0, ("alloc_sub_specified: Out of memory!\n"));
580 for (b = s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) {
586 t = realloc_string_sub(t, "%N", automount_server(user));
589 if ((h = get_user_home_dir(user)))
590 t = realloc_string_sub(t, "%H", h);
593 t = realloc_string_sub(t, "%P", connectpath);
596 t = realloc_string_sub(t, "%S", lp_servicename(snum));
599 t = realloc_string_sub(t, "%g", gidtoname(gid));
602 t = realloc_string_sub(t, "%u", user);
605 /* Patch from jkf@soton.ac.uk Left the %N (NIS
606 * server name) in standard_sub_basic as it is
607 * a feature for logon servers, hence uses the
608 * username. The %p (NIS server path) code is
609 * here as it is used instead of the default
610 * "path =" string in [homes] and so needs the
611 * service name, not the username. */
613 t = realloc_string_sub(t, "%p", automount_path(lp_servicename(snum)));
628 ret_string = alloc_sub_basic(smb_name, a_string);
633 /****************************************************************************
634 Do some standard substitutions in a string.
635 ****************************************************************************/
637 void standard_sub_conn(connection_struct *conn, char *str, size_t len)
639 standard_sub_advanced(SNUM(conn), conn->user, conn->connectpath,
640 conn->gid, current_user_info.smb_name, str, len);
643 /****************************************************************************
644 Like standard_sub but by snum.
645 ****************************************************************************/
647 void standard_sub_snum(int snum, char *str, size_t len)
649 extern struct current_user current_user;
650 static uid_t cached_uid = -1;
651 static fstring cached_user;
652 /* calling uidtoname() on every substitute would be too expensive, so
653 we cache the result here as nearly every call is for the same uid */
655 if (cached_uid != current_user.uid) {
656 fstrcpy(cached_user, uidtoname(current_user.uid));
657 cached_uid = current_user.uid;
660 standard_sub_advanced(snum, cached_user, "", -1,
661 current_user_info.smb_name, str, len);