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