s3: libsmb: Cleanup in get_dc_list()
[Samba.git] / source3 / lib / substitute.c
blobe359ef89494ed3620b01c964f90b3faa2443ba57
1 /*
2 Unix SMB/CIFS implementation.
3 string substitution functions
4 Copyright (C) Andrew Tridgell 1992-2000
5 Copyright (C) Gerald Carter 2006
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.
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.
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/>.
22 #include "includes.h"
23 #include "system/passwd.h"
24 #include "secrets.h"
25 #include "auth.h"
26 #include "lib/util/string_wrappers.h"
28 /* Max DNS name is 253 + '\0' */
29 #define MACHINE_NAME_SIZE 254
31 static char local_machine[MACHINE_NAME_SIZE];
32 static char remote_machine[MACHINE_NAME_SIZE];
34 userdom_struct current_user_info;
35 fstring remote_proto="UNKNOWN";
37 /**
38 * Set the 'local' machine name
39 * @param local_name the name we are being called
40 * @param if this is the 'final' name for us, not be be changed again
42 bool set_local_machine_name(const char *local_name, bool perm)
44 static bool already_perm = false;
45 char tmp[MACHINE_NAME_SIZE];
47 if (already_perm) {
48 return true;
51 strlcpy(tmp, local_name, sizeof(tmp));
52 trim_char(tmp, ' ', ' ');
54 alpha_strcpy(local_machine,
55 tmp,
56 SAFE_NETBIOS_CHARS,
57 sizeof(local_machine) - 1);
58 if (!strlower_m(local_machine)) {
59 return false;
62 already_perm = perm;
64 return true;
67 const char *get_local_machine_name(void)
69 if (local_machine[0] == '\0') {
70 return lp_netbios_name();
73 return local_machine;
76 /**
77 * Set the 'remote' machine name
79 * @param remote_name the name our client wants to be called by
80 * @param if this is the 'final' name for them, not be be changed again
82 bool set_remote_machine_name(const char *remote_name, bool perm)
84 static bool already_perm = False;
85 char tmp[MACHINE_NAME_SIZE];
87 if (already_perm) {
88 return true;
91 strlcpy(tmp, remote_name, sizeof(tmp));
92 trim_char(tmp, ' ', ' ');
94 alpha_strcpy(remote_machine,
95 tmp,
96 SAFE_NETBIOS_CHARS,
97 sizeof(remote_machine) - 1);
98 if (!strlower_m(remote_machine)) {
99 return false;
102 already_perm = perm;
104 return true;
107 const char *get_remote_machine_name(void)
109 return remote_machine;
112 static char sub_peeraddr[INET6_ADDRSTRLEN];
113 static const char *sub_peername = NULL;
114 static char sub_sockaddr[INET6_ADDRSTRLEN];
116 void sub_set_socket_ids(const char *peeraddr, const char *peername,
117 const char *sockaddr)
119 const char *addr = peeraddr;
121 if (strnequal(addr, "::ffff:", 7)) {
122 addr += 7;
124 strlcpy(sub_peeraddr, addr, sizeof(sub_peeraddr));
126 if (sub_peername != NULL &&
127 sub_peername != sub_peeraddr) {
128 talloc_free(discard_const_p(char,sub_peername));
129 sub_peername = NULL;
131 sub_peername = talloc_strdup(NULL, peername);
132 if (sub_peername == NULL) {
133 sub_peername = sub_peeraddr;
137 * Shouldn't we do the ::ffff: cancellation here as well? The
138 * original code in talloc_sub_basic() did not do it, so I'm
139 * leaving it out here as well for compatibility.
141 strlcpy(sub_sockaddr, sockaddr, sizeof(sub_sockaddr));
144 /*******************************************************************
145 Setup the strings used by substitutions. Called per packet. Ensure
146 %U name is set correctly also.
148 smb_name must be sanitized by alpha_strcpy
149 ********************************************************************/
151 void set_current_user_info(const char *smb_name, const char *unix_name,
152 const char *domain)
154 static const void *last_smb_name;
155 static const void *last_unix_name;
156 static const void *last_domain;
158 if (likely(last_smb_name == smb_name &&
159 last_unix_name == unix_name &&
160 last_domain == domain))
162 return;
165 fstrcpy(current_user_info.smb_name, smb_name);
166 fstrcpy(current_user_info.unix_name, unix_name);
167 fstrcpy(current_user_info.domain, domain);
169 last_smb_name = smb_name;
170 last_unix_name = unix_name;
171 last_domain = domain;
174 /*******************************************************************
175 Return the current active user name.
176 *******************************************************************/
178 const char *get_current_username(void)
180 return current_user_info.smb_name;
183 /*******************************************************************
184 Given a pointer to a %$(NAME) in p and the whole string in str
185 expand it as an environment variable.
186 str must be a talloced string.
187 Return a new allocated and expanded string.
188 Based on code by Branko Cibej <branko.cibej@hermes.si>
189 When this is called p points at the '%' character.
190 May substitute multiple occurrencies of the same env var.
191 ********************************************************************/
193 static char *realloc_expand_env_var(char *str, char *p)
195 char *envname;
196 char *envval;
197 char *q, *r;
198 int copylen;
200 if (p[0] != '%' || p[1] != '$' || p[2] != '(') {
201 return str;
205 * Look for the terminating ')'.
208 if ((q = strchr_m(p,')')) == NULL) {
209 DEBUG(0,("expand_env_var: Unterminated environment variable [%s]\n", p));
210 return str;
214 * Extract the name from within the %$(NAME) string.
217 r = p + 3;
218 copylen = q - r;
220 /* reserve space for use later add %$() chars */
221 if ( (envname = talloc_array(talloc_tos(), char, copylen + 1 + 4)) == NULL ) {
222 return NULL;
225 strncpy(envname,r,copylen);
226 envname[copylen] = '\0';
228 if ((envval = getenv(envname)) == NULL) {
229 DEBUG(0,("expand_env_var: Environment variable [%s] not set\n", envname));
230 TALLOC_FREE(envname);
231 return str;
235 * Copy the full %$(NAME) into envname so it
236 * can be replaced.
239 copylen = q + 1 - p;
240 strncpy(envname,p,copylen);
241 envname[copylen] = '\0';
242 r = realloc_string_sub(str, envname, envval);
243 TALLOC_FREE(envname);
245 return r;
248 /*******************************************************************
249 Patch from jkf@soton.ac.uk
250 Added this to implement %p (NIS auto-map version of %H)
251 *******************************************************************/
253 static const char *automount_path(const char *user_name)
255 TALLOC_CTX *ctx = talloc_tos();
256 const char *server_path;
258 /* use the passwd entry as the default */
259 /* this will be the default if WITH_AUTOMOUNT is not used or fails */
261 server_path = talloc_strdup(ctx, get_user_home_dir(ctx, user_name));
262 if (!server_path) {
263 return "";
266 #if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
268 if (lp_nis_homedir()) {
269 const char *home_path_start;
270 char *automount_value = automount_lookup(ctx, user_name);
272 if(automount_value && strlen(automount_value) > 0) {
273 home_path_start = strchr_m(automount_value,':');
274 if (home_path_start != NULL) {
275 DEBUG(5, ("NIS lookup succeeded. "
276 "Home path is: %s\n",
277 home_path_start ?
278 (home_path_start+1):""));
279 server_path = talloc_strdup(ctx,
280 home_path_start+1);
281 if (!server_path) {
282 server_path = "";
285 } else {
286 /* NIS key lookup failed: default to
287 * user home directory from password file */
288 DEBUG(5, ("NIS lookup failed. Using Home path from "
289 "passwd file. Home path is: %s\n", server_path ));
292 #endif
294 DEBUG(4,("Home server path: %s\n", server_path));
295 return server_path;
298 /*******************************************************************
299 Patch from jkf@soton.ac.uk
300 This is Luke's original function with the NIS lookup code
301 moved out to a separate function.
302 *******************************************************************/
304 static const char *automount_server(const char *user_name)
306 TALLOC_CTX *ctx = talloc_tos();
307 const char *server_name;
308 const char *local_machine_name = get_local_machine_name();
310 /* use the local machine name as the default */
311 /* this will be the default if WITH_AUTOMOUNT is not used or fails */
312 if (local_machine_name && *local_machine_name) {
313 server_name = talloc_strdup(ctx, local_machine_name);
314 } else {
315 server_name = talloc_strdup(ctx, lp_netbios_name());
318 if (!server_name) {
319 return "";
322 #if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
323 if (lp_nis_homedir()) {
324 char *p;
325 char *srv;
326 char *automount_value = automount_lookup(ctx, user_name);
327 if (!automount_value) {
328 return "";
330 srv = talloc_strdup(ctx, automount_value);
331 if (!srv) {
332 return "";
334 p = strchr_m(srv, ':');
335 if (!p) {
336 return "";
338 *p = '\0';
339 server_name = srv;
340 DEBUG(5, ("NIS lookup succeeded. Home server %s\n",
341 server_name));
343 #endif
345 DEBUG(4,("Home server: %s\n", server_name));
346 return server_name;
349 /****************************************************************************
350 Do some standard substitutions in a string.
351 len is the length in bytes of the space allowed in string str. If zero means
352 don't allow expansions.
353 ****************************************************************************/
355 void standard_sub_basic(const char *smb_name, const char *domain_name,
356 char *str, size_t len)
358 char *s;
360 if ( (s = talloc_sub_basic(talloc_tos(), smb_name, domain_name, str )) != NULL ) {
361 strncpy( str, s, len );
364 TALLOC_FREE( s );
368 * Limit addresses to hexalpha charactes and underscore, safe for path
369 * components for Windows clients.
371 static void make_address_pathsafe(char *addr)
373 while(addr && *addr) {
374 if(!isxdigit(*addr)) {
375 *addr = '_';
377 ++addr;
381 /****************************************************************************
382 Do some standard substitutions in a string.
383 This function will return a talloced string that has to be freed.
384 ****************************************************************************/
386 char *talloc_sub_basic(TALLOC_CTX *mem_ctx,
387 const char *smb_name,
388 const char *domain_name,
389 const char *str)
391 char *b, *p, *s, *r, *a_string;
392 fstring pidstr, vnnstr;
393 const char *local_machine_name = get_local_machine_name();
394 TALLOC_CTX *tmp_ctx = NULL;
396 /* workaround to prevent a crash while looking at bug #687 */
398 if (!str) {
399 DEBUG(0,("talloc_sub_basic: NULL source string! This should not happen\n"));
400 return NULL;
403 a_string = talloc_strdup(mem_ctx, str);
404 if (a_string == NULL) {
405 DEBUG(0, ("talloc_sub_basic: Out of memory!\n"));
406 return NULL;
409 tmp_ctx = talloc_stackframe();
411 for (s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) {
413 r = NULL;
414 b = a_string;
416 switch (*(p+1)) {
417 case 'U' :
418 r = strlower_talloc(tmp_ctx, smb_name);
419 if (r == NULL) {
420 goto error;
422 a_string = realloc_string_sub(a_string, "%U", r);
423 break;
424 case 'G' : {
425 struct passwd *pass;
426 bool is_domain_name = false;
427 const char *sep = lp_winbind_separator();
429 if (domain_name != NULL && domain_name[0] != '\0' &&
430 (lp_security() == SEC_ADS ||
431 lp_security() == SEC_DOMAIN)) {
432 r = talloc_asprintf(tmp_ctx,
433 "%s%c%s",
434 domain_name,
435 *sep,
436 smb_name);
437 is_domain_name = true;
438 } else {
439 r = talloc_strdup(tmp_ctx, smb_name);
441 if (r == NULL) {
442 goto error;
445 pass = Get_Pwnam_alloc(tmp_ctx, r);
446 if (pass != NULL) {
447 char *group_name;
449 group_name = gidtoname(pass->pw_gid);
450 if (is_domain_name) {
451 char *group_sep;
452 group_sep = strchr_m(group_name, *sep);
453 if (group_sep != NULL) {
454 group_name = group_sep + 1;
457 a_string = realloc_string_sub(a_string,
458 "%G",
459 group_name);
461 TALLOC_FREE(pass);
462 break;
464 case 'D' :
465 r = strupper_talloc(tmp_ctx, domain_name);
466 if (r == NULL) {
467 goto error;
469 a_string = realloc_string_sub(a_string, "%D", r);
470 break;
471 case 'I' : {
472 a_string = realloc_string_sub(
473 a_string, "%I",
474 sub_peeraddr[0] ? sub_peeraddr : "0.0.0.0");
475 break;
477 case 'J' : {
478 r = talloc_strdup(tmp_ctx,
479 sub_peeraddr[0] ? sub_peeraddr : "0.0.0.0");
480 make_address_pathsafe(r);
481 a_string = realloc_string_sub(a_string, "%J", r);
482 break;
484 case 'i':
485 a_string = realloc_string_sub(
486 a_string, "%i",
487 sub_sockaddr[0] ? sub_sockaddr : "0.0.0.0");
488 break;
489 case 'j' : {
490 r = talloc_strdup(tmp_ctx,
491 sub_sockaddr[0] ? sub_sockaddr : "0.0.0.0");
492 make_address_pathsafe(r);
493 a_string = realloc_string_sub(a_string, "%j", r);
494 break;
496 case 'L' :
497 if ( strncasecmp_m(p, "%LOGONSERVER%", strlen("%LOGONSERVER%")) == 0 ) {
498 break;
500 if (local_machine_name && *local_machine_name) {
501 a_string = realloc_string_sub(a_string, "%L", local_machine_name);
502 } else {
503 a_string = realloc_string_sub(a_string, "%L", lp_netbios_name());
505 break;
506 case 'N':
507 a_string = realloc_string_sub(a_string, "%N", automount_server(smb_name));
508 break;
509 case 'M' :
510 a_string = realloc_string_sub(a_string, "%M",
511 sub_peername ? sub_peername : "");
512 break;
513 case 'R' :
514 a_string = realloc_string_sub(a_string, "%R", remote_proto);
515 break;
516 case 'T' :
517 a_string = realloc_string_sub(a_string, "%T", current_timestring(tmp_ctx, False));
518 break;
519 case 't' :
520 a_string = realloc_string_sub(a_string, "%t",
521 current_minimal_timestring(tmp_ctx, False));
522 break;
523 case 'a' :
524 a_string = realloc_string_sub(a_string, "%a",
525 get_remote_arch_str());
526 break;
527 case 'd' :
528 slprintf(pidstr,sizeof(pidstr)-1, "%d",(int)getpid());
529 a_string = realloc_string_sub(a_string, "%d", pidstr);
530 break;
531 case 'h' :
532 a_string = realloc_string_sub(a_string, "%h", myhostname());
533 break;
534 case 'm' :
535 a_string = realloc_string_sub(a_string, "%m",
536 remote_machine);
537 break;
538 case 'v' :
539 a_string = realloc_string_sub(a_string, "%v", samba_version_string());
540 break;
541 case 'w' :
542 a_string = realloc_string_sub(a_string, "%w", lp_winbind_separator());
543 break;
544 case '$' :
545 a_string = realloc_expand_env_var(a_string, p); /* Expand environment variables */
546 break;
547 case 'V' :
548 slprintf(vnnstr,sizeof(vnnstr)-1, "%u", get_my_vnn());
549 a_string = realloc_string_sub(a_string, "%V", vnnstr);
550 break;
551 default:
552 break;
555 p++;
556 TALLOC_FREE(r);
558 if (a_string == NULL) {
559 goto done;
563 goto done;
565 error:
566 TALLOC_FREE(a_string);
568 done:
569 TALLOC_FREE(tmp_ctx);
570 return a_string;
573 /****************************************************************************
574 Do some specific substitutions in a string.
575 This function will return an allocated string that have to be freed.
576 ****************************************************************************/
578 char *talloc_sub_specified(TALLOC_CTX *mem_ctx,
579 const char *input_string,
580 const char *username,
581 const char *grpname,
582 const char *domain,
583 uid_t uid,
584 gid_t gid)
586 char *a_string;
587 char *ret_string = NULL;
588 char *b, *p, *s;
589 TALLOC_CTX *tmp_ctx;
591 if (!(tmp_ctx = talloc_new(mem_ctx))) {
592 DEBUG(0, ("talloc_new failed\n"));
593 return NULL;
596 a_string = talloc_strdup(tmp_ctx, input_string);
597 if (a_string == NULL) {
598 DEBUG(0, ("talloc_sub_specified: Out of memory!\n"));
599 goto done;
602 for (s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) {
604 b = a_string;
606 switch (*(p+1)) {
607 case 'U' :
608 a_string = talloc_string_sub(
609 tmp_ctx, a_string, "%U", username);
610 break;
611 case 'u' :
612 a_string = talloc_string_sub(
613 tmp_ctx, a_string, "%u", username);
614 break;
615 case 'G' :
616 if (gid != -1) {
617 const char *name;
619 if (grpname != NULL) {
620 name = grpname;
621 } else {
622 name = gidtoname(gid);
625 a_string = talloc_string_sub(tmp_ctx,
626 a_string,
627 "%G",
628 name);
629 } else {
630 a_string = talloc_string_sub(
631 tmp_ctx, a_string,
632 "%G", "NO_GROUP");
634 break;
635 case 'g' :
636 if (gid != -1) {
637 const char *name;
639 if (grpname != NULL) {
640 name = grpname;
641 } else {
642 name = gidtoname(gid);
645 a_string = talloc_string_sub(tmp_ctx,
646 a_string,
647 "%g",
648 name);
649 } else {
650 a_string = talloc_string_sub(
651 tmp_ctx, a_string, "%g", "NO_GROUP");
653 break;
654 case 'D' :
655 a_string = talloc_string_sub(tmp_ctx, a_string,
656 "%D", domain);
657 break;
658 case 'N' :
659 a_string = talloc_string_sub(
660 tmp_ctx, a_string, "%N",
661 automount_server(username));
662 break;
663 default:
664 break;
667 p++;
668 if (a_string == NULL) {
669 goto done;
673 /* Watch out, using "mem_ctx" here, so all intermediate stuff goes
674 * away with the TALLOC_FREE(tmp_ctx) further down. */
676 ret_string = talloc_sub_basic(mem_ctx, username, domain, a_string);
678 done:
679 TALLOC_FREE(tmp_ctx);
680 return ret_string;
683 /****************************************************************************
684 ****************************************************************************/
686 char *talloc_sub_advanced(TALLOC_CTX *ctx,
687 const char *servicename,
688 const char *user,
689 const char *connectpath,
690 gid_t gid,
691 const char *str)
693 char *a_string;
694 char *b, *p, *s;
696 a_string = talloc_strdup(talloc_tos(), str);
697 if (a_string == NULL) {
698 DEBUG(0, ("talloc_sub_advanced_only: Out of memory!\n"));
699 return NULL;
702 for (s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) {
704 b = a_string;
706 switch (*(p+1)) {
707 case 'N' :
708 a_string = realloc_string_sub(a_string, "%N", automount_server(user));
709 break;
710 case 'H': {
711 char *h;
712 if ((h = get_user_home_dir(talloc_tos(), user)))
713 a_string = realloc_string_sub(a_string, "%H", h);
714 TALLOC_FREE(h);
715 break;
717 case 'P':
718 a_string = realloc_string_sub(a_string, "%P", connectpath);
719 break;
720 case 'S':
721 a_string = realloc_string_sub(a_string, "%S", servicename);
722 break;
723 case 'g':
724 a_string = realloc_string_sub(a_string, "%g", gidtoname(gid));
725 break;
726 case 'u':
727 a_string = realloc_string_sub(a_string, "%u", user);
728 break;
730 /* Patch from jkf@soton.ac.uk Left the %N (NIS
731 * server name) in standard_sub_basic as it is
732 * a feature for logon servers, hence uses the
733 * username. The %p (NIS server path) code is
734 * here as it is used instead of the default
735 * "path =" string in [homes] and so needs the
736 * service name, not the username. */
737 case 'p':
738 a_string = realloc_string_sub(a_string, "%p",
739 automount_path(servicename));
740 break;
742 default:
743 break;
746 p++;
747 if (a_string == NULL) {
748 return NULL;
752 return a_string;
755 char *talloc_sub_full(TALLOC_CTX *ctx,
756 const char *servicename,
757 const char *user,
758 const char *connectpath,
759 gid_t gid,
760 const char *smb_name,
761 const char *domain_name,
762 const char *str)
764 char *a_string, *ret_string;
766 a_string = talloc_sub_advanced(ctx, servicename, user, connectpath,
767 gid, str);
768 if (a_string == NULL) {
769 return NULL;
772 ret_string = talloc_sub_basic(ctx, smb_name, domain_name, a_string);
773 TALLOC_FREE(a_string);
774 return ret_string;