ctdb-daemon: Fix signed/unsigned comparison
[samba.git] / source3 / lib / substitute.c
blob833af10b6f03faebbc4a64b357e8a6729f59b62a
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"
27 /* Max DNS name is 253 + '\0' */
28 #define MACHINE_NAME_SIZE 254
30 static char local_machine[MACHINE_NAME_SIZE];
31 static char remote_machine[MACHINE_NAME_SIZE];
33 userdom_struct current_user_info;
34 fstring remote_proto="UNKNOWN";
36 /**
37 * Set the 'local' machine name
38 * @param local_name the name we are being called
39 * @param if this is the 'final' name for us, not be be changed again
41 bool set_local_machine_name(const char *local_name, bool perm)
43 static bool already_perm = false;
44 char tmp[MACHINE_NAME_SIZE];
46 if (already_perm) {
47 return true;
50 strlcpy(tmp, local_name, sizeof(tmp));
51 trim_char(tmp, ' ', ' ');
53 alpha_strcpy(local_machine,
54 tmp,
55 SAFE_NETBIOS_CHARS,
56 sizeof(local_machine) - 1);
57 if (!strlower_m(local_machine)) {
58 return false;
61 already_perm = perm;
63 return true;
66 const char *get_local_machine_name(void)
68 if (local_machine[0] == '\0') {
69 return lp_netbios_name();
72 return local_machine;
75 /**
76 * Set the 'remote' machine name
78 * @param remote_name the name our client wants to be called by
79 * @param if this is the 'final' name for them, not be be changed again
81 bool set_remote_machine_name(const char *remote_name, bool perm)
83 static bool already_perm = False;
84 char tmp[MACHINE_NAME_SIZE];
86 if (already_perm) {
87 return true;
90 strlcpy(tmp, remote_name, sizeof(tmp));
91 trim_char(tmp, ' ', ' ');
93 alpha_strcpy(remote_machine,
94 tmp,
95 SAFE_NETBIOS_CHARS,
96 sizeof(remote_machine) - 1);
97 if (!strlower_m(remote_machine)) {
98 return false;
101 already_perm = perm;
103 return true;
106 const char *get_remote_machine_name(void)
108 return remote_machine;
111 static char sub_peeraddr[INET6_ADDRSTRLEN];
112 static const char *sub_peername = NULL;
113 static char sub_sockaddr[INET6_ADDRSTRLEN];
115 void sub_set_socket_ids(const char *peeraddr, const char *peername,
116 const char *sockaddr)
118 const char *addr = peeraddr;
120 if (strnequal(addr, "::ffff:", 7)) {
121 addr += 7;
123 strlcpy(sub_peeraddr, addr, sizeof(sub_peeraddr));
125 if (sub_peername != NULL &&
126 sub_peername != sub_peeraddr) {
127 talloc_free(discard_const_p(char,sub_peername));
128 sub_peername = NULL;
130 sub_peername = talloc_strdup(NULL, peername);
131 if (sub_peername == NULL) {
132 sub_peername = sub_peeraddr;
136 * Shouldn't we do the ::ffff: cancellation here as well? The
137 * original code in talloc_sub_basic() did not do it, so I'm
138 * leaving it out here as well for compatibility.
140 strlcpy(sub_sockaddr, sockaddr, sizeof(sub_sockaddr));
143 /*******************************************************************
144 Setup the strings used by substitutions. Called per packet. Ensure
145 %U name is set correctly also.
147 smb_name must be sanitized by alpha_strcpy
148 ********************************************************************/
150 void set_current_user_info(const char *smb_name, const char *unix_name,
151 const char *domain)
153 static const void *last_smb_name;
154 static const void *last_unix_name;
155 static const void *last_domain;
157 if (likely(last_smb_name == smb_name &&
158 last_unix_name == unix_name &&
159 last_domain == domain))
161 return;
164 fstrcpy(current_user_info.smb_name, smb_name);
165 fstrcpy(current_user_info.unix_name, unix_name);
166 fstrcpy(current_user_info.domain, domain);
168 last_smb_name = smb_name;
169 last_unix_name = unix_name;
170 last_domain = domain;
173 /*******************************************************************
174 Return the current active user name.
175 *******************************************************************/
177 const char *get_current_username(void)
179 return current_user_info.smb_name;
182 /*******************************************************************
183 Given a pointer to a %$(NAME) in p and the whole string in str
184 expand it as an environment variable.
185 str must be a talloced string.
186 Return a new allocated and expanded string.
187 Based on code by Branko Cibej <branko.cibej@hermes.si>
188 When this is called p points at the '%' character.
189 May substitute multiple occurrencies of the same env var.
190 ********************************************************************/
192 static char *realloc_expand_env_var(char *str, char *p)
194 char *envname;
195 char *envval;
196 char *q, *r;
197 int copylen;
199 if (p[0] != '%' || p[1] != '$' || p[2] != '(') {
200 return str;
204 * Look for the terminating ')'.
207 if ((q = strchr_m(p,')')) == NULL) {
208 DEBUG(0,("expand_env_var: Unterminated environment variable [%s]\n", p));
209 return str;
213 * Extract the name from within the %$(NAME) string.
216 r = p + 3;
217 copylen = q - r;
219 /* reserve space for use later add %$() chars */
220 if ( (envname = talloc_array(talloc_tos(), char, copylen + 1 + 4)) == NULL ) {
221 return NULL;
224 strncpy(envname,r,copylen);
225 envname[copylen] = '\0';
227 if ((envval = getenv(envname)) == NULL) {
228 DEBUG(0,("expand_env_var: Environment variable [%s] not set\n", envname));
229 TALLOC_FREE(envname);
230 return str;
234 * Copy the full %$(NAME) into envname so it
235 * can be replaced.
238 copylen = q + 1 - p;
239 strncpy(envname,p,copylen);
240 envname[copylen] = '\0';
241 r = realloc_string_sub(str, envname, envval);
242 TALLOC_FREE(envname);
244 return r;
247 /*******************************************************************
248 Patch from jkf@soton.ac.uk
249 Added this to implement %p (NIS auto-map version of %H)
250 *******************************************************************/
252 static const char *automount_path(const char *user_name)
254 TALLOC_CTX *ctx = talloc_tos();
255 const char *server_path;
257 /* use the passwd entry as the default */
258 /* this will be the default if WITH_AUTOMOUNT is not used or fails */
260 server_path = talloc_strdup(ctx, get_user_home_dir(ctx, user_name));
261 if (!server_path) {
262 return "";
265 #if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
267 if (lp_nis_homedir()) {
268 const char *home_path_start;
269 char *automount_value = automount_lookup(ctx, user_name);
271 if(automount_value && strlen(automount_value) > 0) {
272 home_path_start = strchr_m(automount_value,':');
273 if (home_path_start != NULL) {
274 DEBUG(5, ("NIS lookup succeeded. "
275 "Home path is: %s\n",
276 home_path_start ?
277 (home_path_start+1):""));
278 server_path = talloc_strdup(ctx,
279 home_path_start+1);
280 if (!server_path) {
281 server_path = "";
284 } else {
285 /* NIS key lookup failed: default to
286 * user home directory from password file */
287 DEBUG(5, ("NIS lookup failed. Using Home path from "
288 "passwd file. Home path is: %s\n", server_path ));
291 #endif
293 DEBUG(4,("Home server path: %s\n", server_path));
294 return server_path;
297 /*******************************************************************
298 Patch from jkf@soton.ac.uk
299 This is Luke's original function with the NIS lookup code
300 moved out to a separate function.
301 *******************************************************************/
303 static const char *automount_server(const char *user_name)
305 TALLOC_CTX *ctx = talloc_tos();
306 const char *server_name;
307 const char *local_machine_name = get_local_machine_name();
309 /* use the local machine name as the default */
310 /* this will be the default if WITH_AUTOMOUNT is not used or fails */
311 if (local_machine_name && *local_machine_name) {
312 server_name = talloc_strdup(ctx, local_machine_name);
313 } else {
314 server_name = talloc_strdup(ctx, lp_netbios_name());
317 if (!server_name) {
318 return "";
321 #if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
322 if (lp_nis_homedir()) {
323 char *p;
324 char *srv;
325 char *automount_value = automount_lookup(ctx, user_name);
326 if (!automount_value) {
327 return "";
329 srv = talloc_strdup(ctx, automount_value);
330 if (!srv) {
331 return "";
333 p = strchr_m(srv, ':');
334 if (!p) {
335 return "";
337 *p = '\0';
338 server_name = srv;
339 DEBUG(5, ("NIS lookup succeeded. Home server %s\n",
340 server_name));
342 #endif
344 DEBUG(4,("Home server: %s\n", server_name));
345 return server_name;
348 /****************************************************************************
349 Do some standard substitutions in a string.
350 len is the length in bytes of the space allowed in string str. If zero means
351 don't allow expansions.
352 ****************************************************************************/
354 void standard_sub_basic(const char *smb_name, const char *domain_name,
355 char *str, size_t len)
357 char *s;
359 if ( (s = talloc_sub_basic(talloc_tos(), smb_name, domain_name, str )) != NULL ) {
360 strncpy( str, s, len );
363 TALLOC_FREE( s );
367 * Limit addresses to hexalpha charactes and underscore, safe for path
368 * components for Windows clients.
370 static void make_address_pathsafe(char *addr)
372 while(addr && *addr) {
373 if(!isxdigit(*addr)) {
374 *addr = '_';
376 ++addr;
380 /****************************************************************************
381 Do some standard substitutions in a string.
382 This function will return a talloced string that has to be freed.
383 ****************************************************************************/
385 char *talloc_sub_basic(TALLOC_CTX *mem_ctx,
386 const char *smb_name,
387 const char *domain_name,
388 const char *str)
390 char *b, *p, *s, *r, *a_string;
391 fstring pidstr, vnnstr;
392 const char *local_machine_name = get_local_machine_name();
393 TALLOC_CTX *tmp_ctx = NULL;
395 /* workaround to prevent a crash while looking at bug #687 */
397 if (!str) {
398 DEBUG(0,("talloc_sub_basic: NULL source string! This should not happen\n"));
399 return NULL;
402 a_string = talloc_strdup(mem_ctx, str);
403 if (a_string == NULL) {
404 DEBUG(0, ("talloc_sub_basic: Out of memory!\n"));
405 return NULL;
408 tmp_ctx = talloc_stackframe();
410 for (s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) {
412 r = NULL;
413 b = a_string;
415 switch (*(p+1)) {
416 case 'U' :
417 r = strlower_talloc(tmp_ctx, smb_name);
418 if (r == NULL) {
419 goto error;
421 a_string = realloc_string_sub(a_string, "%U", r);
422 break;
423 case 'G' : {
424 struct passwd *pass;
425 bool is_domain_name = false;
426 const char *sep = lp_winbind_separator();
428 if (domain_name != NULL && domain_name[0] != '\0' &&
429 (lp_security() == SEC_ADS ||
430 lp_security() == SEC_DOMAIN)) {
431 r = talloc_asprintf(tmp_ctx,
432 "%s%c%s",
433 domain_name,
434 *sep,
435 smb_name);
436 is_domain_name = true;
437 } else {
438 r = talloc_strdup(tmp_ctx, smb_name);
440 if (r == NULL) {
441 goto error;
444 pass = Get_Pwnam_alloc(tmp_ctx, r);
445 if (pass != NULL) {
446 char *group_name;
448 group_name = gidtoname(pass->pw_gid);
449 if (is_domain_name) {
450 char *group_sep;
451 group_sep = strchr_m(group_name, *sep);
452 if (group_sep != NULL) {
453 group_name = group_sep + 1;
456 a_string = realloc_string_sub(a_string,
457 "%G",
458 group_name);
460 TALLOC_FREE(pass);
461 break;
463 case 'D' :
464 r = strupper_talloc(tmp_ctx, domain_name);
465 if (r == NULL) {
466 goto error;
468 a_string = realloc_string_sub(a_string, "%D", r);
469 break;
470 case 'I' : {
471 a_string = realloc_string_sub(
472 a_string, "%I",
473 sub_peeraddr[0] ? sub_peeraddr : "0.0.0.0");
474 break;
476 case 'J' : {
477 r = talloc_strdup(tmp_ctx,
478 sub_peeraddr[0] ? sub_peeraddr : "0.0.0.0");
479 make_address_pathsafe(r);
480 a_string = realloc_string_sub(a_string, "%J", r);
481 break;
483 case 'i':
484 a_string = realloc_string_sub(
485 a_string, "%i",
486 sub_sockaddr[0] ? sub_sockaddr : "0.0.0.0");
487 break;
488 case 'j' : {
489 r = talloc_strdup(tmp_ctx,
490 sub_sockaddr[0] ? sub_sockaddr : "0.0.0.0");
491 make_address_pathsafe(r);
492 a_string = realloc_string_sub(a_string, "%j", r);
493 break;
495 case 'L' :
496 if ( strncasecmp_m(p, "%LOGONSERVER%", strlen("%LOGONSERVER%")) == 0 ) {
497 break;
499 if (local_machine_name && *local_machine_name) {
500 a_string = realloc_string_sub(a_string, "%L", local_machine_name);
501 } else {
502 a_string = realloc_string_sub(a_string, "%L", lp_netbios_name());
504 break;
505 case 'N':
506 a_string = realloc_string_sub(a_string, "%N", automount_server(smb_name));
507 break;
508 case 'M' :
509 a_string = realloc_string_sub(a_string, "%M",
510 sub_peername ? sub_peername : "");
511 break;
512 case 'R' :
513 a_string = realloc_string_sub(a_string, "%R", remote_proto);
514 break;
515 case 'T' :
516 a_string = realloc_string_sub(a_string, "%T", current_timestring(tmp_ctx, False));
517 break;
518 case 't' :
519 a_string = realloc_string_sub(a_string, "%t",
520 current_minimal_timestring(tmp_ctx, False));
521 break;
522 case 'a' :
523 a_string = realloc_string_sub(a_string, "%a",
524 get_remote_arch_str());
525 break;
526 case 'd' :
527 slprintf(pidstr,sizeof(pidstr)-1, "%d",(int)getpid());
528 a_string = realloc_string_sub(a_string, "%d", pidstr);
529 break;
530 case 'h' :
531 a_string = realloc_string_sub(a_string, "%h", myhostname());
532 break;
533 case 'm' :
534 a_string = realloc_string_sub(a_string, "%m",
535 remote_machine);
536 break;
537 case 'v' :
538 a_string = realloc_string_sub(a_string, "%v", samba_version_string());
539 break;
540 case 'w' :
541 a_string = realloc_string_sub(a_string, "%w", lp_winbind_separator());
542 break;
543 case '$' :
544 a_string = realloc_expand_env_var(a_string, p); /* Expand environment variables */
545 break;
546 case 'V' :
547 slprintf(vnnstr,sizeof(vnnstr)-1, "%u", get_my_vnn());
548 a_string = realloc_string_sub(a_string, "%V", vnnstr);
549 break;
550 default:
551 break;
554 p++;
555 TALLOC_FREE(r);
557 if (a_string == NULL) {
558 goto done;
562 goto done;
564 error:
565 TALLOC_FREE(a_string);
567 done:
568 TALLOC_FREE(tmp_ctx);
569 return a_string;
572 /****************************************************************************
573 Do some specific substitutions in a string.
574 This function will return an allocated string that have to be freed.
575 ****************************************************************************/
577 char *talloc_sub_specified(TALLOC_CTX *mem_ctx,
578 const char *input_string,
579 const char *username,
580 const char *grpname,
581 const char *domain,
582 uid_t uid,
583 gid_t gid)
585 char *a_string;
586 char *ret_string = NULL;
587 char *b, *p, *s;
588 TALLOC_CTX *tmp_ctx;
590 if (!(tmp_ctx = talloc_new(mem_ctx))) {
591 DEBUG(0, ("talloc_new failed\n"));
592 return NULL;
595 a_string = talloc_strdup(tmp_ctx, input_string);
596 if (a_string == NULL) {
597 DEBUG(0, ("talloc_sub_specified: Out of memory!\n"));
598 goto done;
601 for (s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) {
603 b = a_string;
605 switch (*(p+1)) {
606 case 'U' :
607 a_string = talloc_string_sub(
608 tmp_ctx, a_string, "%U", username);
609 break;
610 case 'u' :
611 a_string = talloc_string_sub(
612 tmp_ctx, a_string, "%u", username);
613 break;
614 case 'G' :
615 if (gid != -1) {
616 const char *name;
618 if (grpname != NULL) {
619 name = grpname;
620 } else {
621 name = gidtoname(gid);
624 a_string = talloc_string_sub(tmp_ctx,
625 a_string,
626 "%G",
627 name);
628 } else {
629 a_string = talloc_string_sub(
630 tmp_ctx, a_string,
631 "%G", "NO_GROUP");
633 break;
634 case 'g' :
635 if (gid != -1) {
636 const char *name;
638 if (grpname != NULL) {
639 name = grpname;
640 } else {
641 name = gidtoname(gid);
644 a_string = talloc_string_sub(tmp_ctx,
645 a_string,
646 "%g",
647 name);
648 } else {
649 a_string = talloc_string_sub(
650 tmp_ctx, a_string, "%g", "NO_GROUP");
652 break;
653 case 'D' :
654 a_string = talloc_string_sub(tmp_ctx, a_string,
655 "%D", domain);
656 break;
657 case 'N' :
658 a_string = talloc_string_sub(
659 tmp_ctx, a_string, "%N",
660 automount_server(username));
661 break;
662 default:
663 break;
666 p++;
667 if (a_string == NULL) {
668 goto done;
672 /* Watch out, using "mem_ctx" here, so all intermediate stuff goes
673 * away with the TALLOC_FREE(tmp_ctx) further down. */
675 ret_string = talloc_sub_basic(mem_ctx, username, domain, a_string);
677 done:
678 TALLOC_FREE(tmp_ctx);
679 return ret_string;
682 /****************************************************************************
683 ****************************************************************************/
685 char *talloc_sub_advanced(TALLOC_CTX *ctx,
686 const char *servicename,
687 const char *user,
688 const char *connectpath,
689 gid_t gid,
690 const char *str)
692 char *a_string;
693 char *b, *p, *s;
695 a_string = talloc_strdup(talloc_tos(), str);
696 if (a_string == NULL) {
697 DEBUG(0, ("talloc_sub_advanced_only: Out of memory!\n"));
698 return NULL;
701 for (s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) {
703 b = a_string;
705 switch (*(p+1)) {
706 case 'N' :
707 a_string = realloc_string_sub(a_string, "%N", automount_server(user));
708 break;
709 case 'H': {
710 char *h;
711 if ((h = get_user_home_dir(talloc_tos(), user)))
712 a_string = realloc_string_sub(a_string, "%H", h);
713 TALLOC_FREE(h);
714 break;
716 case 'P':
717 a_string = realloc_string_sub(a_string, "%P", connectpath);
718 break;
719 case 'S':
720 a_string = realloc_string_sub(a_string, "%S", servicename);
721 break;
722 case 'g':
723 a_string = realloc_string_sub(a_string, "%g", gidtoname(gid));
724 break;
725 case 'u':
726 a_string = realloc_string_sub(a_string, "%u", user);
727 break;
729 /* Patch from jkf@soton.ac.uk Left the %N (NIS
730 * server name) in standard_sub_basic as it is
731 * a feature for logon servers, hence uses the
732 * username. The %p (NIS server path) code is
733 * here as it is used instead of the default
734 * "path =" string in [homes] and so needs the
735 * service name, not the username. */
736 case 'p':
737 a_string = realloc_string_sub(a_string, "%p",
738 automount_path(servicename));
739 break;
741 default:
742 break;
745 p++;
746 if (a_string == NULL) {
747 return NULL;
751 return a_string;
754 char *talloc_sub_full(TALLOC_CTX *ctx,
755 const char *servicename,
756 const char *user,
757 const char *connectpath,
758 gid_t gid,
759 const char *smb_name,
760 const char *domain_name,
761 const char *str)
763 char *a_string, *ret_string;
765 a_string = talloc_sub_advanced(ctx, servicename, user, connectpath,
766 gid, str);
767 if (a_string == NULL) {
768 return NULL;
771 ret_string = talloc_sub_basic(ctx, smb_name, domain_name, a_string);
772 TALLOC_FREE(a_string);
773 return ret_string;