Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : string substitution functions
4 : Copyright (C) Andrew Tridgell 1992-2000
5 : Copyright (C) Gerald Carter 2006
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 :
22 : #include "includes.h"
23 : #include "substitute.h"
24 : #include "system/passwd.h"
25 : #include "secrets.h"
26 : #include "auth.h"
27 : #include "lib/util/string_wrappers.h"
28 :
29 : /* Max DNS name is 253 + '\0' */
30 : #define MACHINE_NAME_SIZE 254
31 :
32 : static char local_machine[MACHINE_NAME_SIZE];
33 : static char remote_machine[MACHINE_NAME_SIZE];
34 :
35 : userdom_struct current_user_info;
36 : static fstring remote_proto="UNKNOWN";
37 :
38 65149 : void set_remote_proto(const char *proto)
39 : {
40 65149 : fstrcpy(remote_proto, proto);
41 65149 : }
42 :
43 : /**
44 : * Set the 'local' machine name
45 : * @param local_name the name we are being called
46 : * @param if this is the 'final' name for us, not be be changed again
47 : */
48 1038 : bool set_local_machine_name(const char *local_name, bool perm)
49 : {
50 0 : static bool already_perm = false;
51 0 : char tmp[MACHINE_NAME_SIZE];
52 :
53 1038 : if (already_perm) {
54 0 : return true;
55 : }
56 :
57 1038 : strlcpy(tmp, local_name, sizeof(tmp));
58 1038 : trim_char(tmp, ' ', ' ');
59 :
60 1038 : alpha_strcpy(local_machine,
61 : tmp,
62 : SAFE_NETBIOS_CHARS,
63 : sizeof(local_machine) - 1);
64 1038 : if (!strlower_m(local_machine)) {
65 0 : return false;
66 : }
67 :
68 1038 : already_perm = perm;
69 :
70 1038 : return true;
71 : }
72 :
73 18922505 : const char *get_local_machine_name(void)
74 : {
75 18922505 : if (local_machine[0] == '\0') {
76 18396972 : return lp_netbios_name();
77 : }
78 :
79 525533 : return local_machine;
80 : }
81 :
82 : /**
83 : * Set the 'remote' machine name
84 : *
85 : * @param remote_name the name our client wants to be called by
86 : * @param if this is the 'final' name for them, not be be changed again
87 : */
88 56251 : bool set_remote_machine_name(const char *remote_name, bool perm)
89 : {
90 842 : static bool already_perm = False;
91 842 : char tmp[MACHINE_NAME_SIZE];
92 :
93 56251 : if (already_perm) {
94 4359 : return true;
95 : }
96 :
97 51892 : strlcpy(tmp, remote_name, sizeof(tmp));
98 51892 : trim_char(tmp, ' ', ' ');
99 :
100 51892 : alpha_strcpy(remote_machine,
101 : tmp,
102 : SAFE_NETBIOS_CHARS,
103 : sizeof(remote_machine) - 1);
104 51892 : if (!strlower_m(remote_machine)) {
105 0 : return false;
106 : }
107 :
108 51892 : already_perm = perm;
109 :
110 51892 : return true;
111 : }
112 :
113 1099 : const char *get_remote_machine_name(void)
114 : {
115 1099 : return remote_machine;
116 : }
117 :
118 : static char sub_peeraddr[INET6_ADDRSTRLEN];
119 : static const char *sub_peername = NULL;
120 : static char sub_sockaddr[INET6_ADDRSTRLEN];
121 :
122 31563 : void sub_set_socket_ids(const char *peeraddr, const char *peername,
123 : const char *sockaddr)
124 : {
125 31563 : const char *addr = peeraddr;
126 :
127 31563 : if (strnequal(addr, "::ffff:", 7)) {
128 0 : addr += 7;
129 : }
130 31563 : strlcpy(sub_peeraddr, addr, sizeof(sub_peeraddr));
131 :
132 31563 : if (sub_peername != NULL &&
133 0 : sub_peername != sub_peeraddr) {
134 0 : talloc_free(discard_const_p(char,sub_peername));
135 0 : sub_peername = NULL;
136 : }
137 31563 : sub_peername = talloc_strdup(NULL, peername);
138 31563 : if (sub_peername == NULL) {
139 0 : sub_peername = sub_peeraddr;
140 : }
141 :
142 : /*
143 : * Shouldn't we do the ::ffff: cancellation here as well? The
144 : * original code in talloc_sub_basic() did not do it, so I'm
145 : * leaving it out here as well for compatibility.
146 : */
147 31563 : strlcpy(sub_sockaddr, sockaddr, sizeof(sub_sockaddr));
148 31563 : }
149 :
150 : /*******************************************************************
151 : Setup the strings used by substitutions. Called per packet. Ensure
152 : %U name is set correctly also.
153 :
154 : smb_name must be sanitized by alpha_strcpy
155 : ********************************************************************/
156 :
157 4985813 : void set_current_user_info(const char *smb_name, const char *unix_name,
158 : const char *domain)
159 : {
160 11031 : static const void *last_smb_name;
161 11031 : static const void *last_unix_name;
162 11031 : static const void *last_domain;
163 :
164 4985813 : if (likely(last_smb_name == smb_name &&
165 : last_unix_name == unix_name &&
166 : last_domain == domain))
167 : {
168 4417114 : return;
169 : }
170 :
171 560810 : fstrcpy(current_user_info.smb_name, smb_name);
172 560810 : fstrcpy(current_user_info.unix_name, unix_name);
173 560810 : fstrcpy(current_user_info.domain, domain);
174 :
175 560810 : last_smb_name = smb_name;
176 560810 : last_unix_name = unix_name;
177 560810 : last_domain = domain;
178 : }
179 :
180 : /*******************************************************************
181 : Return the current active user name.
182 : *******************************************************************/
183 :
184 18390446 : const char *get_current_username(void)
185 : {
186 18390446 : return current_user_info.smb_name;
187 : }
188 :
189 18356208 : const char *get_current_user_info_domain(void)
190 : {
191 18356208 : return current_user_info.domain;
192 : }
193 :
194 : /*******************************************************************
195 : Given a pointer to a %$(NAME) in p and the whole string in str
196 : expand it as an environment variable.
197 : str must be a talloced string.
198 : Return a new allocated and expanded string.
199 : Based on code by Branko Cibej <branko.cibej@hermes.si>
200 : When this is called p points at the '%' character.
201 : May substitute multiple occurrences of the same env var.
202 : ********************************************************************/
203 :
204 0 : static char *realloc_expand_env_var(char *str, char *p)
205 : {
206 0 : char *envname;
207 0 : char *envval;
208 0 : char *q, *r;
209 0 : int copylen;
210 :
211 0 : if (p[0] != '%' || p[1] != '$' || p[2] != '(') {
212 0 : return str;
213 : }
214 :
215 : /*
216 : * Look for the terminating ')'.
217 : */
218 :
219 0 : if ((q = strchr_m(p,')')) == NULL) {
220 0 : DEBUG(0,("expand_env_var: Unterminated environment variable [%s]\n", p));
221 0 : return str;
222 : }
223 :
224 : /*
225 : * Extract the name from within the %$(NAME) string.
226 : */
227 :
228 0 : r = p + 3;
229 0 : copylen = q - r;
230 :
231 : /* reserve space for use later add %$() chars */
232 0 : if ( (envname = talloc_array(talloc_tos(), char, copylen + 1 + 4)) == NULL ) {
233 0 : return NULL;
234 : }
235 :
236 0 : strncpy(envname,r,copylen);
237 0 : envname[copylen] = '\0';
238 :
239 0 : if ((envval = getenv(envname)) == NULL) {
240 0 : DEBUG(0,("expand_env_var: Environment variable [%s] not set\n", envname));
241 0 : TALLOC_FREE(envname);
242 0 : return str;
243 : }
244 :
245 : /*
246 : * Copy the full %$(NAME) into envname so it
247 : * can be replaced.
248 : */
249 :
250 0 : copylen = q + 1 - p;
251 0 : strncpy(envname,p,copylen);
252 0 : envname[copylen] = '\0';
253 0 : r = realloc_string_sub(str, envname, envval);
254 0 : TALLOC_FREE(envname);
255 :
256 0 : return r;
257 : }
258 :
259 : /****************************************************************************
260 : Do some standard substitutions in a string.
261 : len is the length in bytes of the space allowed in string str. If zero means
262 : don't allow expansions.
263 : ****************************************************************************/
264 :
265 14951061 : void standard_sub_basic(const char *smb_name, const char *domain_name,
266 : char *str, size_t len)
267 : {
268 57307 : char *s;
269 :
270 14951061 : if ( (s = talloc_sub_basic(talloc_tos(), smb_name, domain_name, str )) != NULL ) {
271 14951061 : strncpy( str, s, len );
272 : }
273 :
274 14951061 : TALLOC_FREE( s );
275 14951061 : }
276 :
277 : /*
278 : * Limit addresses to hexalpha characters and underscore, safe for path
279 : * components for Windows clients.
280 : */
281 1695 : static void make_address_pathsafe(char *addr)
282 : {
283 13560 : while(addr && *addr) {
284 11865 : if(!isxdigit(*addr)) {
285 5085 : *addr = '_';
286 : }
287 11865 : ++addr;
288 : }
289 1695 : }
290 :
291 : /****************************************************************************
292 : Do some standard substitutions in a string.
293 : This function will return a talloced string that has to be freed.
294 : ****************************************************************************/
295 :
296 18920808 : char *talloc_sub_basic(TALLOC_CTX *mem_ctx,
297 : const char *smb_name,
298 : const char *domain_name,
299 : const char *str)
300 : {
301 90294 : char *b, *p, *s, *r, *a_string;
302 90294 : fstring pidstr, vnnstr;
303 18920808 : const char *local_machine_name = get_local_machine_name();
304 18920808 : TALLOC_CTX *tmp_ctx = NULL;
305 :
306 : /* workaround to prevent a crash while looking at bug #687 */
307 :
308 18920808 : if (!str) {
309 0 : DEBUG(0,("talloc_sub_basic: NULL source string! This should not happen\n"));
310 0 : return NULL;
311 : }
312 :
313 18920808 : a_string = talloc_strdup(mem_ctx, str);
314 18920808 : if (a_string == NULL) {
315 0 : DEBUG(0, ("talloc_sub_basic: Out of memory!\n"));
316 0 : return NULL;
317 : }
318 :
319 18920808 : tmp_ctx = talloc_stackframe();
320 :
321 19573163 : for (s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) {
322 :
323 562061 : r = NULL;
324 562061 : b = a_string;
325 :
326 562061 : switch (*(p+1)) {
327 326793 : case 'U' :
328 326793 : r = strlower_talloc(tmp_ctx, smb_name);
329 326793 : if (r == NULL) {
330 0 : goto error;
331 : }
332 326793 : a_string = realloc_string_sub(a_string, "%U", r);
333 326793 : break;
334 64 : case 'G' : {
335 0 : struct passwd *pass;
336 64 : bool is_domain_name = false;
337 64 : const char *sep = lp_winbind_separator();
338 :
339 126 : if (domain_name != NULL && domain_name[0] != '\0' &&
340 62 : (lp_security() == SEC_ADS ||
341 0 : lp_security() == SEC_DOMAIN)) {
342 62 : r = talloc_asprintf(tmp_ctx,
343 : "%s%c%s",
344 : domain_name,
345 62 : *sep,
346 : smb_name);
347 62 : is_domain_name = true;
348 : } else {
349 2 : r = talloc_strdup(tmp_ctx, smb_name);
350 : }
351 64 : if (r == NULL) {
352 0 : goto error;
353 : }
354 :
355 64 : pass = Get_Pwnam_alloc(tmp_ctx, r);
356 64 : if (pass != NULL) {
357 0 : char *group_name;
358 :
359 36 : group_name = gidtoname(pass->pw_gid);
360 36 : if (is_domain_name) {
361 0 : char *group_sep;
362 36 : group_sep = strchr_m(group_name, *sep);
363 36 : if (group_sep != NULL) {
364 36 : group_name = group_sep + 1;
365 : }
366 : }
367 36 : a_string = realloc_string_sub(a_string,
368 : "%G",
369 : group_name);
370 : }
371 64 : TALLOC_FREE(pass);
372 64 : break;
373 : }
374 183 : case 'D' :
375 183 : r = strupper_talloc(tmp_ctx, domain_name);
376 183 : if (r == NULL) {
377 0 : goto error;
378 : }
379 183 : a_string = realloc_string_sub(a_string, "%D", r);
380 183 : break;
381 3 : case 'I' : {
382 4 : a_string = realloc_string_sub(
383 : a_string, "%I",
384 3 : sub_peeraddr[0] ? sub_peeraddr : "0.0.0.0");
385 3 : break;
386 : }
387 1 : case 'J' : {
388 1 : r = talloc_strdup(tmp_ctx,
389 1 : sub_peeraddr[0] ? sub_peeraddr : "0.0.0.0");
390 1 : make_address_pathsafe(r);
391 1 : a_string = realloc_string_sub(a_string, "%J", r);
392 1 : break;
393 : }
394 3 : case 'i':
395 4 : a_string = realloc_string_sub(
396 : a_string, "%i",
397 3 : sub_sockaddr[0] ? sub_sockaddr : "0.0.0.0");
398 3 : break;
399 1694 : case 'j' : {
400 1694 : r = talloc_strdup(tmp_ctx,
401 1694 : sub_sockaddr[0] ? sub_sockaddr : "0.0.0.0");
402 1694 : make_address_pathsafe(r);
403 1694 : a_string = realloc_string_sub(a_string, "%j", r);
404 1694 : break;
405 : }
406 6 : case 'L' :
407 6 : if ( strncasecmp_m(p, "%LOGONSERVER%", strlen("%LOGONSERVER%")) == 0 ) {
408 0 : break;
409 : }
410 6 : if (local_machine_name && *local_machine_name) {
411 6 : a_string = realloc_string_sub(a_string, "%L", local_machine_name);
412 : } else {
413 0 : a_string = realloc_string_sub(a_string, "%L", lp_netbios_name());
414 : }
415 6 : break;
416 187938 : case 'N' :
417 187938 : a_string = realloc_string_sub(a_string,
418 : "%N",
419 : lp_netbios_name());
420 187938 : break;
421 2 : case 'M' :
422 2 : a_string = realloc_string_sub(a_string, "%M",
423 2 : sub_peername ? sub_peername : "");
424 2 : break;
425 2 : case 'R' :
426 2 : a_string = realloc_string_sub(a_string, "%R", remote_proto);
427 2 : break;
428 2 : case 'T' :
429 2 : a_string = realloc_string_sub(a_string, "%T", current_timestring(tmp_ctx, False));
430 2 : break;
431 172 : case 't' :
432 172 : a_string = realloc_string_sub(a_string, "%t",
433 172 : current_minimal_timestring(tmp_ctx, False));
434 172 : break;
435 2 : case 'a' :
436 2 : a_string = realloc_string_sub(a_string, "%a",
437 : get_remote_arch_str());
438 2 : break;
439 2 : case 'd' :
440 2 : slprintf(pidstr,sizeof(pidstr)-1, "%d",(int)getpid());
441 2 : a_string = realloc_string_sub(a_string, "%d", pidstr);
442 2 : break;
443 2 : case 'h' :
444 2 : a_string = realloc_string_sub(a_string, "%h", myhostname());
445 2 : break;
446 44214 : case 'm' :
447 44214 : a_string = realloc_string_sub(a_string, "%m",
448 : remote_machine);
449 44214 : break;
450 2 : case 'v' :
451 2 : a_string = realloc_string_sub(a_string, "%v", samba_version_string());
452 2 : break;
453 2 : case 'w' :
454 2 : a_string = realloc_string_sub(a_string, "%w", lp_winbind_separator());
455 2 : break;
456 0 : case '$' :
457 0 : a_string = realloc_expand_env_var(a_string, p); /* Expand environment variables */
458 0 : break;
459 2 : case 'V' :
460 2 : slprintf(vnnstr,sizeof(vnnstr)-1, "%u", get_my_vnn());
461 2 : a_string = realloc_string_sub(a_string, "%V", vnnstr);
462 2 : break;
463 972 : default:
464 972 : break;
465 : }
466 :
467 562061 : p++;
468 562061 : TALLOC_FREE(r);
469 :
470 562061 : if (a_string == NULL) {
471 0 : goto done;
472 : }
473 : }
474 :
475 18920808 : goto done;
476 :
477 0 : error:
478 0 : TALLOC_FREE(a_string);
479 :
480 90294 : done:
481 18920808 : TALLOC_FREE(tmp_ctx);
482 18830514 : return a_string;
483 : }
484 :
485 : /****************************************************************************
486 : Do some specific substitutions in a string.
487 : This function will return an allocated string that have to be freed.
488 : ****************************************************************************/
489 :
490 215357 : char *talloc_sub_specified(TALLOC_CTX *mem_ctx,
491 : const char *input_string,
492 : const char *username,
493 : const char *grpname,
494 : const char *domain,
495 : uid_t uid,
496 : gid_t gid)
497 : {
498 9 : char *a_string;
499 215357 : char *ret_string = NULL;
500 9 : char *b, *p, *s;
501 9 : TALLOC_CTX *tmp_ctx;
502 :
503 215357 : if (!(tmp_ctx = talloc_new(mem_ctx))) {
504 0 : DEBUG(0, ("talloc_new failed\n"));
505 0 : return NULL;
506 : }
507 :
508 215357 : a_string = talloc_strdup(tmp_ctx, input_string);
509 215357 : if (a_string == NULL) {
510 0 : DEBUG(0, ("talloc_sub_specified: Out of memory!\n"));
511 0 : goto done;
512 : }
513 :
514 432624 : for (s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) {
515 :
516 217267 : b = a_string;
517 :
518 217267 : switch (*(p+1)) {
519 107674 : case 'U' :
520 107674 : a_string = talloc_string_sub(
521 : tmp_ctx, a_string, "%U", username);
522 107674 : break;
523 2 : case 'u' :
524 2 : a_string = talloc_string_sub(
525 : tmp_ctx, a_string, "%u", username);
526 2 : break;
527 1912 : case 'G' :
528 1912 : if (gid != -1) {
529 1 : const char *name;
530 :
531 1911 : if (grpname != NULL) {
532 1910 : name = grpname;
533 : } else {
534 1 : name = gidtoname(gid);
535 : }
536 :
537 1911 : a_string = talloc_string_sub(tmp_ctx,
538 : a_string,
539 : "%G",
540 : name);
541 : } else {
542 1 : a_string = talloc_string_sub(
543 : tmp_ctx, a_string,
544 : "%G", "NO_GROUP");
545 : }
546 1910 : break;
547 2 : case 'g' :
548 2 : if (gid != -1) {
549 1 : const char *name;
550 :
551 1 : if (grpname != NULL) {
552 0 : name = grpname;
553 : } else {
554 1 : name = gidtoname(gid);
555 : }
556 :
557 1 : a_string = talloc_string_sub(tmp_ctx,
558 : a_string,
559 : "%g",
560 : name);
561 : } else {
562 1 : a_string = talloc_string_sub(
563 : tmp_ctx, a_string, "%g", "NO_GROUP");
564 : }
565 0 : break;
566 102199 : case 'D' :
567 102199 : a_string = talloc_string_sub(tmp_ctx, a_string,
568 : "%D", domain);
569 102199 : break;
570 5474 : case 'N' :
571 5474 : a_string = talloc_string_sub(tmp_ctx, a_string,
572 : "%N", lp_netbios_name());
573 5474 : break;
574 0 : default:
575 0 : break;
576 : }
577 :
578 217267 : p++;
579 217267 : if (a_string == NULL) {
580 0 : goto done;
581 : }
582 : }
583 :
584 : /* Watch out, using "mem_ctx" here, so all intermediate stuff goes
585 : * away with the TALLOC_FREE(tmp_ctx) further down. */
586 :
587 215357 : ret_string = talloc_sub_basic(mem_ctx, username, domain, a_string);
588 :
589 215357 : done:
590 215357 : TALLOC_FREE(tmp_ctx);
591 215357 : return ret_string;
592 : }
593 :
594 : /****************************************************************************
595 : ****************************************************************************/
596 :
597 71760 : char *talloc_sub_advanced(TALLOC_CTX *ctx,
598 : const char *servicename,
599 : const char *user,
600 : const char *connectpath,
601 : gid_t gid,
602 : const char *str)
603 : {
604 759 : char *a_string;
605 759 : char *b, *p, *s;
606 :
607 71760 : a_string = talloc_strdup(talloc_tos(), str);
608 71760 : if (a_string == NULL) {
609 0 : DEBUG(0, ("talloc_sub_advanced_only: Out of memory!\n"));
610 0 : return NULL;
611 : }
612 :
613 74169 : for (s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) {
614 :
615 2409 : b = a_string;
616 :
617 2409 : switch (*(p+1)) {
618 0 : case 'N':
619 0 : a_string = realloc_string_sub(a_string,
620 : "%N",
621 : lp_netbios_name());
622 0 : break;
623 0 : case 'H': {
624 0 : char *h;
625 0 : if ((h = get_user_home_dir(talloc_tos(), user)))
626 0 : a_string = realloc_string_sub(a_string, "%H", h);
627 0 : TALLOC_FREE(h);
628 0 : break;
629 : }
630 10 : case 'P':
631 10 : a_string = realloc_string_sub(a_string, "%P", connectpath);
632 10 : break;
633 0 : case 'S':
634 0 : a_string = realloc_string_sub(a_string, "%S", servicename);
635 0 : break;
636 2 : case 'g':
637 2 : a_string = realloc_string_sub(a_string, "%g", gidtoname(gid));
638 2 : break;
639 36 : case 'u':
640 36 : a_string = realloc_string_sub(a_string, "%u", user);
641 36 : break;
642 2361 : default:
643 2361 : break;
644 : }
645 :
646 2409 : p++;
647 2409 : if (a_string == NULL) {
648 0 : return NULL;
649 : }
650 : }
651 :
652 71001 : return a_string;
653 : }
654 :
655 70938 : char *talloc_sub_full(TALLOC_CTX *ctx,
656 : const char *servicename,
657 : const char *user,
658 : const char *connectpath,
659 : gid_t gid,
660 : const char *smb_name,
661 : const char *domain_name,
662 : const char *str)
663 : {
664 759 : char *a_string, *ret_string;
665 :
666 70938 : a_string = talloc_sub_advanced(ctx, servicename, user, connectpath,
667 : gid, str);
668 70938 : if (a_string == NULL) {
669 0 : return NULL;
670 : }
671 :
672 70938 : ret_string = talloc_sub_basic(ctx, smb_name, domain_name, a_string);
673 70938 : TALLOC_FREE(a_string);
674 70938 : return ret_string;
675 : }
|