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