r14075: * add support for long variable names in smb.conf in the form of %(....)
[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 2 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, char *str, size_t len)
419 {
420         char *s;
421         
422         if ( (s = alloc_sub_basic( smb_name, str )) != NULL ) {
423                 strncpy( str, s, len );
424         }
425         
426         SAFE_FREE( s );
427         
428 }
429
430 /****************************************************************************
431  Do some standard substitutions in a string.
432  This function will return an allocated string that have to be freed.
433 ****************************************************************************/
434
435 char *talloc_sub_basic(TALLOC_CTX *mem_ctx, const char *smb_name, const char *str)
436 {
437         char *a, *t;
438         
439         if ( (a = alloc_sub_basic(smb_name, str)) == NULL ) {
440                 return NULL;
441         }
442         t = talloc_strdup(mem_ctx, a);
443         SAFE_FREE(a);
444         return t;
445 }
446
447 /****************************************************************************
448 ****************************************************************************/
449
450 char *alloc_sub_basic(const char *smb_name, const char *str)
451 {
452         char *b, *p, *s, *r, *a_string;
453         fstring pidstr;
454         struct passwd *pass;
455         const char *local_machine_name = get_local_machine_name();
456
457         /* workaround to prevent a crash while looking at bug #687 */
458         
459         if (!str) {
460                 DEBUG(0,("alloc_sub_basic: NULL source string!  This should not happen\n"));
461                 return NULL;
462         }
463         
464         a_string = SMB_STRDUP(str);
465         if (a_string == NULL) {
466                 DEBUG(0, ("alloc_sub_specified: Out of memory!\n"));
467                 return NULL;
468         }
469         
470         for (b = s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) {
471
472                 r = NULL;
473                 b = a_string;
474                 
475                 switch (*(p+1)) {
476                 case 'U' : 
477                         r = strdup_lower(smb_name);
478                         if (r == NULL) {
479                                 goto error;
480                         }
481                         a_string = realloc_string_sub(a_string, "%U", r);
482                         break;
483                 case 'G' :
484                         r = SMB_STRDUP(smb_name);
485                         if (r == NULL) {
486                                 goto error;
487                         }
488                         if ((pass = Get_Pwnam(r))!=NULL) {
489                                 a_string = realloc_string_sub(a_string, "%G", gidtoname(pass->pw_gid));
490                         } 
491                         break;
492                 case 'D' :
493                         r = strdup_upper(current_user_info.domain);
494                         if (r == NULL) {
495                                 goto error;
496                         }
497                         a_string = realloc_string_sub(a_string, "%D", r);
498                         break;
499                 case 'I' :
500                         a_string = realloc_string_sub(a_string, "%I", client_addr());
501                         break;
502                 case 'i': 
503                         a_string = realloc_string_sub( a_string, "%i", client_socket_addr() );
504                         break;
505                 case 'L' : 
506                         if ( StrnCaseCmp(p, "%LOGONSERVER%", strlen("%LOGONSERVER%")) == 0 ) {
507                                 break;
508                         }
509                         if (local_machine_name && *local_machine_name) {
510                                 a_string = realloc_string_sub(a_string, "%L", local_machine_name); 
511                         } else {
512                                 a_string = realloc_string_sub(a_string, "%L", global_myname()); 
513                         }
514                         break;
515                 case 'N':
516                         a_string = realloc_string_sub(a_string, "%N", automount_server(smb_name));
517                         break;
518                 case 'M' :
519                         a_string = realloc_string_sub(a_string, "%M", client_name());
520                         break;
521                 case 'R' :
522                         a_string = realloc_string_sub(a_string, "%R", remote_proto);
523                         break;
524                 case 'T' :
525                         a_string = realloc_string_sub(a_string, "%T", timestring(False));
526                         break;
527                 case 'a' :
528                         a_string = realloc_string_sub(a_string, "%a", remote_arch);
529                         break;
530                 case 'd' :
531                         slprintf(pidstr,sizeof(pidstr)-1, "%d",(int)sys_getpid());
532                         a_string = realloc_string_sub(a_string, "%d", pidstr);
533                         break;
534                 case 'h' :
535                         a_string = realloc_string_sub(a_string, "%h", myhostname());
536                         break;
537                 case 'm' :
538                         a_string = realloc_string_sub(a_string, "%m", remote_machine);
539                         break;
540                 case 'v' :
541                         a_string = realloc_string_sub(a_string, "%v", SAMBA_VERSION_STRING);
542                         break;
543                 case 'w' :
544                         a_string = realloc_string_sub(a_string, "%w", lp_winbind_separator());
545                         break;
546                 case '$' :
547                         a_string = realloc_expand_env_var(a_string, p); /* Expand environment variables */
548                         break;
549                 case '(':
550                         a_string = realloc_expand_longvar( a_string, p );
551                         break;
552                 default: 
553                         break;
554                 }
555
556                 p++;
557                 SAFE_FREE(r);
558                 
559                 if ( !a_string ) {
560                         return NULL;
561                 }
562         }
563
564         return a_string;
565
566 error:
567         SAFE_FREE(a_string);
568         return NULL;
569 }
570
571 /****************************************************************************
572  Do some specific substitutions in a string.
573  This function will return an allocated string that have to be freed.
574 ****************************************************************************/
575
576 char *talloc_sub_specified(TALLOC_CTX *mem_ctx,
577                         const char *input_string,
578                         const char *username,
579                         const char *domain,
580                         uid_t uid,
581                         gid_t gid)
582 {
583         char *a, *t;
584         a = alloc_sub_specified(input_string, username, domain, uid, gid);
585         if (!a) {
586                 return NULL;
587         }
588         t = talloc_strdup(mem_ctx, a);
589         SAFE_FREE(a);
590         return t;
591 }
592
593 /****************************************************************************
594 ****************************************************************************/
595
596 char *alloc_sub_specified(const char *input_string,
597                         const char *username,
598                         const char *domain,
599                         uid_t uid,
600                         gid_t gid)
601 {
602         char *a_string, *ret_string;
603         char *b, *p, *s;
604
605         a_string = SMB_STRDUP(input_string);
606         if (a_string == NULL) {
607                 DEBUG(0, ("alloc_sub_specified: Out of memory!\n"));
608                 return NULL;
609         }
610         
611         for (b = s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) {
612                 
613                 b = a_string;
614                 
615                 switch (*(p+1)) {
616                 case 'U' : 
617                         a_string = realloc_string_sub(a_string, "%U", username);
618                         break;
619                 case 'u' : 
620                         a_string = realloc_string_sub(a_string, "%u", username);
621                         break;
622                 case 'G' :
623                         if (gid != -1) {
624                                 a_string = realloc_string_sub(a_string, "%G", gidtoname(gid));
625                         } else {
626                                 a_string = realloc_string_sub(a_string, "%G", "NO_GROUP");
627                         }
628                         break;
629                 case 'g' :
630                         if (gid != -1) {
631                                 a_string = realloc_string_sub(a_string, "%g", gidtoname(gid));
632                         } else {
633                                 a_string = realloc_string_sub(a_string, "%g", "NO_GROUP");
634                         }
635                         break;
636                 case 'D' :
637                         a_string = realloc_string_sub(a_string, "%D", domain);
638                         break;
639                 case 'N' : 
640                         a_string = realloc_string_sub(a_string, "%N", automount_server(username)); 
641                         break;
642                 default: 
643                         break;
644                 }
645
646                 p++;
647                 if (a_string == NULL) {
648                         return NULL;
649                 }
650         }
651
652         ret_string = alloc_sub_basic(username, a_string);
653         SAFE_FREE(a_string);
654         return ret_string;
655 }
656
657 /****************************************************************************
658 ****************************************************************************/
659
660 char *talloc_sub_advanced(TALLOC_CTX *mem_ctx,
661                         int snum,
662                         const char *user,
663                         const char *connectpath,
664                         gid_t gid,
665                         const char *smb_name,
666                         const char *str)
667 {
668         char *a, *t;
669         a = alloc_sub_advanced(snum, user, connectpath, gid, smb_name, str);
670         if (!a) {
671                 return NULL;
672         }
673         t = talloc_strdup(mem_ctx, a);
674         SAFE_FREE(a);
675         return t;
676 }
677
678 /****************************************************************************
679 ****************************************************************************/
680
681 char *alloc_sub_advanced(int snum, const char *user, 
682                                   const char *connectpath, gid_t gid, 
683                                   const char *smb_name, const char *str)
684 {
685         char *a_string, *ret_string;
686         char *b, *p, *s, *h;
687
688         a_string = SMB_STRDUP(str);
689         if (a_string == NULL) {
690                 DEBUG(0, ("alloc_sub_specified: Out of memory!\n"));
691                 return NULL;
692         }
693         
694         for (b = s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) {
695                 
696                 b = a_string;
697                 
698                 switch (*(p+1)) {
699                 case 'N' :
700                         a_string = realloc_string_sub(a_string, "%N", automount_server(user));
701                         break;
702                 case 'H':
703                         if ((h = get_user_home_dir(user)))
704                                 a_string = realloc_string_sub(a_string, "%H", h);
705                         break;
706                 case 'P': 
707                         a_string = realloc_string_sub(a_string, "%P", connectpath); 
708                         break;
709                 case 'S': 
710                         a_string = realloc_string_sub(a_string, "%S", lp_servicename(snum)); 
711                         break;
712                 case 'g': 
713                         a_string = realloc_string_sub(a_string, "%g", gidtoname(gid)); 
714                         break;
715                 case 'u': 
716                         a_string = realloc_string_sub(a_string, "%u", user); 
717                         break;
718                         
719                         /* Patch from jkf@soton.ac.uk Left the %N (NIS
720                          * server name) in standard_sub_basic as it is
721                          * a feature for logon servers, hence uses the
722                          * username.  The %p (NIS server path) code is
723                          * here as it is used instead of the default
724                          * "path =" string in [homes] and so needs the
725                          * service name, not the username.  */
726                 case 'p': 
727                         a_string = realloc_string_sub(a_string, "%p", automount_path(lp_servicename(snum))); 
728                         break;
729                         
730                 default: 
731                         break;
732                 }
733
734                 p++;
735                 if (a_string == NULL) {
736                         return NULL;
737                 }
738         }
739
740         ret_string = alloc_sub_basic(smb_name, a_string);
741         SAFE_FREE(a_string);
742         return ret_string;
743 }
744
745 /****************************************************************************
746  Do some standard substitutions in a string.
747 ****************************************************************************/
748
749 void standard_sub_conn(connection_struct *conn, char *str, size_t len)
750 {
751         char *s;
752         
753         s = alloc_sub_advanced(SNUM(conn), conn->user, conn->connectpath,
754                         conn->gid, smb_user_name, str);
755
756         if ( s ) {
757                 strncpy( str, s, len );
758                 SAFE_FREE( s );
759         }
760 }
761
762 /****************************************************************************
763 ****************************************************************************/
764
765 char *talloc_sub_conn(TALLOC_CTX *mem_ctx, connection_struct *conn, const char *str)
766 {
767         return talloc_sub_advanced(mem_ctx, SNUM(conn), conn->user,
768                         conn->connectpath, conn->gid,
769                         smb_user_name, str);
770 }
771
772 /****************************************************************************
773 ****************************************************************************/
774
775 char *alloc_sub_conn(connection_struct *conn, const char *str)
776 {
777         return alloc_sub_advanced(SNUM(conn), conn->user, conn->connectpath,
778                         conn->gid, smb_user_name, str);
779 }
780
781 /****************************************************************************
782  Like standard_sub but by snum.
783 ****************************************************************************/
784
785 void standard_sub_snum(int snum, char *str, size_t len)
786 {
787         static uid_t cached_uid = -1;
788         static fstring cached_user;
789         char *s;
790         
791         /* calling uidtoname() on every substitute would be too expensive, so
792            we cache the result here as nearly every call is for the same uid */
793
794         if (cached_uid != current_user.ut.uid) {
795                 fstrcpy(cached_user, uidtoname(current_user.ut.uid));
796                 cached_uid = current_user.ut.uid;
797         }
798
799         s = alloc_sub_advanced(snum, cached_user, "", current_user.ut.gid,
800                               smb_user_name, str);
801
802         if ( s ) {
803                 strncpy( str, s, len );
804                 SAFE_FREE( s );
805         }
806 }