r4088: Get medieval on our ass about malloc.... :-). Take control of all our allocation
[abartlet/samba.git/.git] / source3 / lib / substitute.c
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
24 fstring local_machine="";
25 fstring remote_arch="UNKNOWN";
26 userdom_struct current_user_info;
27 fstring remote_proto="UNKNOWN";
28
29 static fstring remote_machine;
30 static 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
38 void 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
71 void 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
87 const char* get_remote_machine_name(void) 
88 {
89         return remote_machine;
90 }
91
92 const 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
105 void 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
119 char* 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
129 void 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  Given a pointer to a %$(NAME) expand it as an environment variable.
139  Return the number of characters by which the pointer should be advanced.
140  Based on code by Branko Cibej <branko.cibej@hermes.si>
141  When this is called p points at the '%' character.
142 ********************************************************************/
143
144 static size_t expand_env_var(char *p, int len)
145 {
146         fstring envname;
147         char *envval;
148         char *q, *r;
149         int copylen;
150
151         if (p[1] != '$')
152                 return 1;
153
154         if (p[2] != '(')
155                 return 2;
156
157         /*
158          * Look for the terminating ')'.
159          */
160
161         if ((q = strchr_m(p,')')) == NULL) {
162                 DEBUG(0,("expand_env_var: Unterminated environment variable [%s]\n", p));
163                 return 2;
164         }
165
166         /*
167          * Extract the name from within the %$(NAME) string.
168          */
169
170         r = p+3;
171         copylen = MIN((q-r),(sizeof(envname)-1));
172         strncpy(envname,r,copylen);
173         envname[copylen] = '\0';
174
175         if ((envval = getenv(envname)) == NULL) {
176                 DEBUG(0,("expand_env_var: Environment variable [%s] not set\n", envname));
177                 return 2;
178         }
179
180         /*
181          * Copy the full %$(NAME) into envname so it
182          * can be replaced.
183          */
184
185         copylen = MIN((q+1-p),(sizeof(envname)-1));
186         strncpy(envname,p,copylen);
187         envname[copylen] = '\0';
188         string_sub(p,envname,envval,len);
189         return 0; /* Allow the environment contents to be parsed. */
190 }
191
192 /*******************************************************************
193  Given a pointer to a %$(NAME) in p and the whole string in str
194  expand it as an environment variable.
195  Return a new allocated and expanded string.
196  Based on code by Branko Cibej <branko.cibej@hermes.si>
197  When this is called p points at the '%' character.
198  May substitute multiple occurrencies of the same env var.
199 ********************************************************************/
200
201
202 static char * realloc_expand_env_var(char *str, char *p)
203 {
204         char *envname;
205         char *envval;
206         char *q, *r;
207         int copylen;
208
209         if (p[0] != '%' || p[1] != '$' || p[2] != '(')
210                 return str;
211
212         /*
213          * Look for the terminating ')'.
214          */
215
216         if ((q = strchr_m(p,')')) == NULL) {
217                 DEBUG(0,("expand_env_var: Unterminated environment variable [%s]\n", p));
218                 return str;
219         }
220
221         /*
222          * Extract the name from within the %$(NAME) string.
223          */
224
225         r = p + 3;
226         copylen = q - r;
227         envname = (char *)SMB_MALLOC(copylen + 1 + 4); /* reserve space for use later add %$() chars */
228         if (envname == NULL) return NULL;
229         strncpy(envname,r,copylen);
230         envname[copylen] = '\0';
231
232         if ((envval = getenv(envname)) == NULL) {
233                 DEBUG(0,("expand_env_var: Environment variable [%s] not set\n", envname));
234                 SAFE_FREE(envname);
235                 return str;
236         }
237
238         /*
239          * Copy the full %$(NAME) into envname so it
240          * can be replaced.
241          */
242
243         copylen = q + 1 - p;
244         strncpy(envname,p,copylen);
245         envname[copylen] = '\0';
246         r = realloc_string_sub(str, envname, envval);
247         SAFE_FREE(envname);
248         if (r == NULL) return NULL;
249         return r;
250 }
251
252 /*******************************************************************
253  Patch from jkf@soton.ac.uk
254  Added this to implement %p (NIS auto-map version of %H)
255 *******************************************************************/
256
257 static char *automount_path(const char *user_name)
258 {
259         static pstring server_path;
260
261         /* use the passwd entry as the default */
262         /* this will be the default if WITH_AUTOMOUNT is not used or fails */
263
264         pstrcpy(server_path, get_user_home_dir(user_name));
265
266 #if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
267
268         if (lp_nis_home_map()) {
269                 char *home_path_start;
270                 char *automount_value = automount_lookup(user_name);
271
272                 if(strlen(automount_value) > 0) {
273                         home_path_start = strchr_m(automount_value,':');
274                         if (home_path_start != NULL) {
275                                 DEBUG(5, ("NIS lookup succeeded.  Home path is: %s\n",
276                                                 home_path_start?(home_path_start+1):""));
277                                 pstrcpy(server_path, home_path_start+1);
278                         }
279                 } else {
280                         /* NIS key lookup failed: default to user home directory from password file */
281                         DEBUG(5, ("NIS lookup failed. Using Home path from passwd file. Home path is: %s\n", server_path ));
282                 }
283         }
284 #endif
285
286         DEBUG(4,("Home server path: %s\n", server_path));
287
288         return server_path;
289 }
290
291 /*******************************************************************
292  Patch from jkf@soton.ac.uk
293  This is Luke's original function with the NIS lookup code
294  moved out to a separate function.
295 *******************************************************************/
296
297 static const char *automount_server(const char *user_name)
298 {
299         static pstring server_name;
300         const char *local_machine_name = get_local_machine_name(); 
301
302         /* use the local machine name as the default */
303         /* this will be the default if WITH_AUTOMOUNT is not used or fails */
304         if (local_machine_name && *local_machine_name)
305                 pstrcpy(server_name, local_machine_name);
306         else
307                 pstrcpy(server_name, global_myname());
308         
309 #if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
310
311         if (lp_nis_home_map()) {
312                 int home_server_len;
313                 char *automount_value = automount_lookup(user_name);
314                 home_server_len = strcspn(automount_value,":");
315                 DEBUG(5, ("NIS lookup succeeded.  Home server length: %d\n",home_server_len));
316                 if (home_server_len > sizeof(pstring))
317                         home_server_len = sizeof(pstring);
318                 strncpy(server_name, automount_value, home_server_len);
319                 server_name[home_server_len] = '\0';
320         }
321 #endif
322
323         DEBUG(4,("Home server: %s\n", server_name));
324
325         return server_name;
326 }
327
328 /****************************************************************************
329  Do some standard substitutions in a string.
330  len is the length in bytes of the space allowed in string str. If zero means
331  don't allow expansions.
332 ****************************************************************************/
333
334 void standard_sub_basic(const char *smb_name, char *str,size_t len)
335 {
336         char *p, *s;
337         fstring pidstr;
338         struct passwd *pass;
339         const char *local_machine_name = get_local_machine_name();
340
341         for (s=str; (p=strchr_m(s, '%'));s=p) {
342                 fstring tmp_str;
343
344                 int l = (int)len - (int)(p-str);
345
346                 if (l < 0)
347                         l = 0;
348                 
349                 switch (*(p+1)) {
350                 case 'U' : 
351                         fstrcpy(tmp_str, smb_name);
352                         strlower_m(tmp_str);
353                         string_sub(p,"%U",tmp_str,l);
354                         break;
355                 case 'G' :
356                         fstrcpy(tmp_str, smb_name);
357                         if ((pass = Get_Pwnam(tmp_str))!=NULL) {
358                                 string_sub(p,"%G",gidtoname(pass->pw_gid),l);
359                         } else {
360                                 p += 2;
361                         }
362                         break;
363                 case 'D' :
364                         fstrcpy(tmp_str, current_user_info.domain);
365                         strupper_m(tmp_str);
366                         string_sub(p,"%D", tmp_str,l);
367                         break;
368                 case 'I' :
369                         string_sub(p,"%I", client_addr(),l);
370                         break;
371                 case 'i' :
372                         string_sub(p,"%i", client_socket_addr(),l);
373                         break;
374                 case 'L' : 
375                         if (local_machine_name && *local_machine_name)
376                                 string_sub(p,"%L", local_machine_name,l); 
377                         else {
378                                 pstring temp_name;
379
380                                 pstrcpy(temp_name, global_myname());
381                                 strlower_m(temp_name);
382                                 string_sub(p,"%L", temp_name,l); 
383                         }
384                         break;
385                 case 'M' :
386                         string_sub(p,"%M", client_name(),l);
387                         break;
388                 case 'R' :
389                         string_sub(p,"%R", remote_proto,l);
390                         break;
391                 case 'T' :
392                         string_sub(p,"%T", timestring(False),l);
393                         break;
394                 case 'a' :
395                         string_sub(p,"%a", remote_arch,l);
396                         break;
397                 case 'd' :
398                         slprintf(pidstr,sizeof(pidstr)-1, "%d",(int)sys_getpid());
399                         string_sub(p,"%d", pidstr,l);
400                         break;
401                 case 'h' :
402                         string_sub(p,"%h", myhostname(),l);
403                         break;
404                 case 'm' :
405                         string_sub(p,"%m", get_remote_machine_name(),l);
406                         break;
407                 case 'v' :
408                         string_sub(p,"%v", SAMBA_VERSION_STRING,l);
409                         break;
410                 case '$' :
411                         p += expand_env_var(p,l);
412                         break; /* Expand environment variables */
413                 case '\0': 
414                         p++; 
415                         break; /* don't run off the end of the string */
416                         
417                 default: p+=2; 
418                         break;
419                 }
420         }
421 }
422
423 static void standard_sub_advanced(int snum, const char *user, 
424                                   const char *connectpath, gid_t gid, 
425                                   const char *smb_name, char *str, size_t len)
426 {
427         char *p, *s, *home;
428
429         for (s=str; (p=strchr_m(s, '%'));s=p) {
430                 int l = (int)len - (int)(p-str);
431         
432                 if (l < 0)
433                         l = 0;
434         
435                 switch (*(p+1)) {
436                 case 'N' :
437                         string_sub(p,"%N", automount_server(user),l);
438                         break;
439                 case 'H':
440                         if ((home = get_user_home_dir(user)))
441                                 string_sub(p,"%H",home, l);
442                         else
443                                 p += 2;
444                         break;
445                 case 'P': 
446                         string_sub(p,"%P", connectpath, l); 
447                         break;
448                 case 'S': 
449                         if ( snum != -1 )
450                                 string_sub(p,"%S", lp_servicename(snum), l); 
451                         break;
452                 case 'g': 
453                         string_sub(p,"%g", gidtoname(gid), l); 
454                         break;
455                 case 'u': 
456                         string_sub(p,"%u", user, l); 
457                         break;
458                         
459                         /* Patch from jkf@soton.ac.uk Left the %N (NIS
460                          * server name) in standard_sub_basic as it is
461                          * a feature for logon servers, hence uses the
462                          * username.  The %p (NIS server path) code is
463                          * here as it is used instead of the default
464                          * "path =" string in [homes] and so needs the
465                          * service name, not the username.  */
466                 case 'p': 
467                         if ( snum != -1 )
468                                 string_sub(p,"%p", automount_path(lp_servicename(snum)), l); 
469                         break;
470                 case '\0': 
471                         p++; 
472                         break; /* don't run off the end of the string */
473                         
474                 default: p+=2; 
475                         break;
476                 }
477         }
478
479         standard_sub_basic(smb_name, str, len);
480 }
481
482 /****************************************************************************
483  Do some standard substitutions in a string.
484  This function will return an allocated string that have to be freed.
485 ****************************************************************************/
486
487 char *talloc_sub_basic(TALLOC_CTX *mem_ctx, const char *smb_name, const char *str)
488 {
489         char *a, *t;
490         a = alloc_sub_basic(smb_name, str);
491         if (!a) return NULL;
492         t = talloc_strdup(mem_ctx, a);
493         SAFE_FREE(a);
494         return t;
495 }
496
497 char *alloc_sub_basic(const char *smb_name, const char *str)
498 {
499         char *b, *p, *s, *t, *r, *a_string;
500         fstring pidstr;
501         struct passwd *pass;
502         const char *local_machine_name = get_local_machine_name();
503
504         /* workaround to prevent a crash while lookinf at bug #687 */
505         
506         if ( !str ) {
507                 DEBUG(0,("alloc_sub_basic: NULL source string!  This should not happen\n"));
508                 return NULL;
509         }
510         
511         a_string = SMB_STRDUP(str);
512         if (a_string == NULL) {
513                 DEBUG(0, ("alloc_sub_specified: Out of memory!\n"));
514                 return NULL;
515         }
516         
517         for (b = s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) {
518
519                 r = NULL;
520                 b = t = a_string;
521                 
522                 switch (*(p+1)) {
523                 case 'U' : 
524                         r = strdup_lower(smb_name);
525                         if (r == NULL) goto error;
526                         t = realloc_string_sub(t, "%U", r);
527                         break;
528                 case 'G' :
529                         r = SMB_STRDUP(smb_name);
530                         if (r == NULL) goto error;
531                         if ((pass = Get_Pwnam(r))!=NULL) {
532                                 t = realloc_string_sub(t, "%G", gidtoname(pass->pw_gid));
533                         } 
534                         break;
535                 case 'D' :
536                         r = strdup_upper(current_user_info.domain);
537                         if (r == NULL) goto error;
538                         t = realloc_string_sub(t, "%D", r);
539                         break;
540                 case 'I' :
541                         t = realloc_string_sub(t, "%I", client_addr());
542                         break;
543                 case 'L' : 
544                         if (local_machine_name && *local_machine_name)
545                                 t = realloc_string_sub(t, "%L", local_machine_name); 
546                         else
547                                 t = realloc_string_sub(t, "%L", global_myname()); 
548                         break;
549                 case 'N':
550                         t = realloc_string_sub(t, "%N", automount_server(smb_name));
551                         break;
552                 case 'M' :
553                         t = realloc_string_sub(t, "%M", client_name());
554                         break;
555                 case 'R' :
556                         t = realloc_string_sub(t, "%R", remote_proto);
557                         break;
558                 case 'T' :
559                         t = realloc_string_sub(t, "%T", timestring(False));
560                         break;
561                 case 'a' :
562                         t = realloc_string_sub(t, "%a", remote_arch);
563                         break;
564                 case 'd' :
565                         slprintf(pidstr,sizeof(pidstr)-1, "%d",(int)sys_getpid());
566                         t = realloc_string_sub(t, "%d", pidstr);
567                         break;
568                 case 'h' :
569                         t = realloc_string_sub(t, "%h", myhostname());
570                         break;
571                 case 'm' :
572                         t = realloc_string_sub(t, "%m", remote_machine);
573                         break;
574                 case 'v' :
575                         t = realloc_string_sub(t, "%v", SAMBA_VERSION_STRING);
576                         break;
577                 case '$' :
578                         t = realloc_expand_env_var(t, p); /* Expand environment variables */
579                         break;
580                         
581                 default: 
582                         break;
583                 }
584
585                 p++;
586                 SAFE_FREE(r);
587                 if (t == NULL) goto error;
588                 a_string = t;
589         }
590
591         return a_string;
592 error:
593         SAFE_FREE(a_string);
594         return NULL;
595 }
596
597 /****************************************************************************
598  Do some specific substitutions in a string.
599  This function will return an allocated string that have to be freed.
600 ****************************************************************************/
601
602 char *talloc_sub_specified(TALLOC_CTX *mem_ctx,
603                         const char *input_string,
604                         const char *username,
605                         const char *domain,
606                         uid_t uid,
607                         gid_t gid)
608 {
609         char *a, *t;
610         a = alloc_sub_specified(input_string, username, domain, uid, gid);
611         if (!a) return NULL;
612         t = talloc_strdup(mem_ctx, a);
613         SAFE_FREE(a);
614         return t;
615 }
616
617 char *alloc_sub_specified(const char *input_string,
618                         const char *username,
619                         const char *domain,
620                         uid_t uid,
621                         gid_t gid)
622 {
623         char *a_string, *ret_string;
624         char *b, *p, *s, *t;
625
626         a_string = SMB_STRDUP(input_string);
627         if (a_string == NULL) {
628                 DEBUG(0, ("alloc_sub_specified: Out of memory!\n"));
629                 return NULL;
630         }
631         
632         for (b = s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) {
633                 
634                 b = t = a_string;
635                 
636                 switch (*(p+1)) {
637                 case 'U' : 
638                         t = realloc_string_sub(t, "%U", username);
639                         break;
640                 case 'u' : 
641                         t = realloc_string_sub(t, "%u", username);
642                         break;
643                 case 'G' :
644                         if (gid != -1) {
645                                 t = realloc_string_sub(t, "%G", gidtoname(gid));
646                         } else {
647                                 t = realloc_string_sub(t, "%G", "NO_GROUP");
648                         }
649                         break;
650                 case 'g' :
651                         if (gid != -1) {
652                                 t = realloc_string_sub(t, "%g", gidtoname(gid));
653                         } else {
654                                 t = realloc_string_sub(t, "%g", "NO_GROUP");
655                         }
656                         break;
657                 case 'D' :
658                         t = realloc_string_sub(t, "%D", domain);
659                         break;
660                 case 'N' : 
661                         t = realloc_string_sub(t, "%N", automount_server(username)); 
662                         break;
663                 default: 
664                         break;
665                 }
666
667                 p++;
668                 if (t == NULL) {
669                         SAFE_FREE(a_string);
670                         return NULL;
671                 }
672                 a_string = t;
673         }
674
675         ret_string = alloc_sub_basic(username, a_string);
676         SAFE_FREE(a_string);
677         return ret_string;
678 }
679
680 char *talloc_sub_advanced(TALLOC_CTX *mem_ctx,
681                         int snum,
682                         const char *user,
683                         const char *connectpath,
684                         gid_t gid,
685                         const char *smb_name,
686                         const char *str)
687 {
688         char *a, *t;
689         a = alloc_sub_advanced(snum, user, connectpath, gid, smb_name, str);
690         if (!a) return NULL;
691         t = talloc_strdup(mem_ctx, a);
692         SAFE_FREE(a);
693         return t;
694 }
695
696 char *alloc_sub_advanced(int snum, const char *user, 
697                                   const char *connectpath, gid_t gid, 
698                                   const char *smb_name, const char *str)
699 {
700         char *a_string, *ret_string;
701         char *b, *p, *s, *t, *h;
702
703         a_string = SMB_STRDUP(str);
704         if (a_string == NULL) {
705                 DEBUG(0, ("alloc_sub_specified: Out of memory!\n"));
706                 return NULL;
707         }
708         
709         for (b = s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) {
710                 
711                 b = t = a_string;
712                 
713                 switch (*(p+1)) {
714                 case 'N' :
715                         t = realloc_string_sub(t, "%N", automount_server(user));
716                         break;
717                 case 'H':
718                         if ((h = get_user_home_dir(user)))
719                                 t = realloc_string_sub(t, "%H", h);
720                         break;
721                 case 'P': 
722                         t = realloc_string_sub(t, "%P", connectpath); 
723                         break;
724                 case 'S': 
725                         t = realloc_string_sub(t, "%S", lp_servicename(snum)); 
726                         break;
727                 case 'g': 
728                         t = realloc_string_sub(t, "%g", gidtoname(gid)); 
729                         break;
730                 case 'u': 
731                         t = realloc_string_sub(t, "%u", user); 
732                         break;
733                         
734                         /* Patch from jkf@soton.ac.uk Left the %N (NIS
735                          * server name) in standard_sub_basic as it is
736                          * a feature for logon servers, hence uses the
737                          * username.  The %p (NIS server path) code is
738                          * here as it is used instead of the default
739                          * "path =" string in [homes] and so needs the
740                          * service name, not the username.  */
741                 case 'p': 
742                         t = realloc_string_sub(t, "%p", automount_path(lp_servicename(snum))); 
743                         break;
744                         
745                 default: 
746                         break;
747                 }
748
749                 p++;
750                 if (t == NULL) {
751                         SAFE_FREE(a_string);
752                         return NULL;
753                 }
754                 a_string = t;
755         }
756
757         ret_string = alloc_sub_basic(smb_name, a_string);
758         SAFE_FREE(a_string);
759         return ret_string;
760 }
761
762 /****************************************************************************
763  Do some standard substitutions in a string.
764 ****************************************************************************/
765
766 void standard_sub_conn(connection_struct *conn, char *str, size_t len)
767 {
768         standard_sub_advanced(SNUM(conn), conn->user, conn->connectpath,
769                         conn->gid, smb_user_name, str, len);
770 }
771
772 char *talloc_sub_conn(TALLOC_CTX *mem_ctx, connection_struct *conn, const char *str)
773 {
774         return talloc_sub_advanced(mem_ctx, SNUM(conn), conn->user,
775                         conn->connectpath, conn->gid,
776                         smb_user_name, str);
777 }
778
779 char *alloc_sub_conn(connection_struct *conn, const char *str)
780 {
781         return alloc_sub_advanced(SNUM(conn), conn->user, conn->connectpath,
782                         conn->gid, smb_user_name, str);
783 }
784
785 /****************************************************************************
786  Like standard_sub but by snum.
787 ****************************************************************************/
788
789 void standard_sub_snum(int snum, char *str, size_t len)
790 {
791         extern struct current_user current_user;
792         static uid_t cached_uid = -1;
793         static fstring cached_user;
794         /* calling uidtoname() on every substitute would be too expensive, so
795            we cache the result here as nearly every call is for the same uid */
796
797         if (cached_uid != current_user.uid) {
798                 fstrcpy(cached_user, uidtoname(current_user.uid));
799                 cached_uid = current_user.uid;
800         }
801
802         standard_sub_advanced(snum, cached_user, "", current_user.gid,
803                               smb_user_name, str, len);
804 }