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 "system/passwd.h"
24 : #include "secrets.h"
25 : #include "auth.h"
26 : #include "lib/util/string_wrappers.h"
27 :
28 : /* Max DNS name is 253 + '\0' */
29 : #define MACHINE_NAME_SIZE 254
30 :
31 : static char local_machine[MACHINE_NAME_SIZE];
32 : static char remote_machine[MACHINE_NAME_SIZE];
33 :
34 : userdom_struct current_user_info;
35 : fstring remote_proto="UNKNOWN";
36 :
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
41 : */
42 1082 : bool set_local_machine_name(const char *local_name, bool perm)
43 : {
44 : static bool already_perm = false;
45 : char tmp[MACHINE_NAME_SIZE];
46 :
47 1082 : if (already_perm) {
48 0 : return true;
49 : }
50 :
51 1082 : strlcpy(tmp, local_name, sizeof(tmp));
52 1082 : trim_char(tmp, ' ', ' ');
53 :
54 1082 : alpha_strcpy(local_machine,
55 : tmp,
56 : SAFE_NETBIOS_CHARS,
57 : sizeof(local_machine) - 1);
58 1082 : if (!strlower_m(local_machine)) {
59 0 : return false;
60 : }
61 :
62 1082 : already_perm = perm;
63 :
64 1082 : return true;
65 : }
66 :
67 13900687 : const char *get_local_machine_name(void)
68 : {
69 13900687 : if (local_machine[0] == '\0') {
70 13412746 : return lp_netbios_name();
71 : }
72 :
73 487941 : return local_machine;
74 : }
75 :
76 : /**
77 : * Set the 'remote' machine name
78 : *
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
81 : */
82 48355 : bool set_remote_machine_name(const char *remote_name, bool perm)
83 : {
84 : static bool already_perm = False;
85 : char tmp[MACHINE_NAME_SIZE];
86 :
87 48355 : if (already_perm) {
88 3447 : return true;
89 : }
90 :
91 44908 : strlcpy(tmp, remote_name, sizeof(tmp));
92 44908 : trim_char(tmp, ' ', ' ');
93 :
94 44908 : alpha_strcpy(remote_machine,
95 : tmp,
96 : SAFE_NETBIOS_CHARS,
97 : sizeof(remote_machine) - 1);
98 44908 : if (!strlower_m(remote_machine)) {
99 0 : return false;
100 : }
101 :
102 44908 : already_perm = perm;
103 :
104 44908 : return true;
105 : }
106 :
107 1149 : const char *get_remote_machine_name(void)
108 : {
109 1149 : return remote_machine;
110 : }
111 :
112 : static char sub_peeraddr[INET6_ADDRSTRLEN];
113 : static const char *sub_peername = NULL;
114 : static char sub_sockaddr[INET6_ADDRSTRLEN];
115 :
116 27259 : void sub_set_socket_ids(const char *peeraddr, const char *peername,
117 : const char *sockaddr)
118 : {
119 27259 : const char *addr = peeraddr;
120 :
121 27259 : if (strnequal(addr, "::ffff:", 7)) {
122 0 : addr += 7;
123 : }
124 27259 : strlcpy(sub_peeraddr, addr, sizeof(sub_peeraddr));
125 :
126 27259 : if (sub_peername != NULL &&
127 0 : sub_peername != sub_peeraddr) {
128 0 : talloc_free(discard_const_p(char,sub_peername));
129 0 : sub_peername = NULL;
130 : }
131 27259 : sub_peername = talloc_strdup(NULL, peername);
132 27259 : if (sub_peername == NULL) {
133 0 : sub_peername = sub_peeraddr;
134 : }
135 :
136 : /*
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.
140 : */
141 27259 : strlcpy(sub_sockaddr, sockaddr, sizeof(sub_sockaddr));
142 27259 : }
143 :
144 : /*******************************************************************
145 : Setup the strings used by substitutions. Called per packet. Ensure
146 : %U name is set correctly also.
147 :
148 : smb_name must be sanitized by alpha_strcpy
149 : ********************************************************************/
150 :
151 5526218 : void set_current_user_info(const char *smb_name, const char *unix_name,
152 : const char *domain)
153 : {
154 : static const void *last_smb_name;
155 : static const void *last_unix_name;
156 : static const void *last_domain;
157 :
158 5526218 : if (likely(last_smb_name == smb_name &&
159 : last_unix_name == unix_name &&
160 : last_domain == domain))
161 : {
162 5166046 : return;
163 : }
164 :
165 354934 : fstrcpy(current_user_info.smb_name, smb_name);
166 354934 : fstrcpy(current_user_info.unix_name, unix_name);
167 354934 : fstrcpy(current_user_info.domain, domain);
168 :
169 354934 : last_smb_name = smb_name;
170 354934 : last_unix_name = unix_name;
171 354934 : last_domain = domain;
172 : }
173 :
174 : /*******************************************************************
175 : Return the current active user name.
176 : *******************************************************************/
177 :
178 13627867 : const char *get_current_username(void)
179 : {
180 13627867 : return current_user_info.smb_name;
181 : }
182 :
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 : ********************************************************************/
192 :
193 0 : static char *realloc_expand_env_var(char *str, char *p)
194 : {
195 : char *envname;
196 : char *envval;
197 : char *q, *r;
198 : int copylen;
199 :
200 0 : if (p[0] != '%' || p[1] != '$' || p[2] != '(') {
201 0 : return str;
202 : }
203 :
204 : /*
205 : * Look for the terminating ')'.
206 : */
207 :
208 0 : if ((q = strchr_m(p,')')) == NULL) {
209 0 : DEBUG(0,("expand_env_var: Unterminated environment variable [%s]\n", p));
210 0 : return str;
211 : }
212 :
213 : /*
214 : * Extract the name from within the %$(NAME) string.
215 : */
216 :
217 0 : r = p + 3;
218 0 : copylen = q - r;
219 :
220 : /* reserve space for use later add %$() chars */
221 0 : if ( (envname = talloc_array(talloc_tos(), char, copylen + 1 + 4)) == NULL ) {
222 0 : return NULL;
223 : }
224 :
225 0 : strncpy(envname,r,copylen);
226 0 : envname[copylen] = '\0';
227 :
228 0 : if ((envval = getenv(envname)) == NULL) {
229 0 : DEBUG(0,("expand_env_var: Environment variable [%s] not set\n", envname));
230 0 : TALLOC_FREE(envname);
231 0 : return str;
232 : }
233 :
234 : /*
235 : * Copy the full %$(NAME) into envname so it
236 : * can be replaced.
237 : */
238 :
239 0 : copylen = q + 1 - p;
240 0 : strncpy(envname,p,copylen);
241 0 : envname[copylen] = '\0';
242 0 : r = realloc_string_sub(str, envname, envval);
243 0 : TALLOC_FREE(envname);
244 :
245 0 : return r;
246 : }
247 :
248 : /****************************************************************************
249 : Do some standard substitutions in a string.
250 : len is the length in bytes of the space allowed in string str. If zero means
251 : don't allow expansions.
252 : ****************************************************************************/
253 :
254 10602120 : void standard_sub_basic(const char *smb_name, const char *domain_name,
255 : char *str, size_t len)
256 : {
257 : char *s;
258 :
259 10602120 : if ( (s = talloc_sub_basic(talloc_tos(), smb_name, domain_name, str )) != NULL ) {
260 10568177 : strncpy( str, s, len );
261 : }
262 :
263 10602120 : TALLOC_FREE( s );
264 10602120 : }
265 :
266 : /*
267 : * Limit addresses to hexalpha charactes and underscore, safe for path
268 : * components for Windows clients.
269 : */
270 1316 : static void make_address_pathsafe(char *addr)
271 : {
272 14816 : while(addr && *addr) {
273 12616 : if(!isxdigit(*addr)) {
274 3948 : *addr = '_';
275 : }
276 12616 : ++addr;
277 : }
278 1316 : }
279 :
280 : /****************************************************************************
281 : Do some standard substitutions in a string.
282 : This function will return a talloced string that has to be freed.
283 : ****************************************************************************/
284 :
285 13898634 : char *talloc_sub_basic(TALLOC_CTX *mem_ctx,
286 : const char *smb_name,
287 : const char *domain_name,
288 : const char *str)
289 : {
290 : char *b, *p, *s, *r, *a_string;
291 : fstring pidstr, vnnstr;
292 13898634 : const char *local_machine_name = get_local_machine_name();
293 13898634 : TALLOC_CTX *tmp_ctx = NULL;
294 :
295 : /* workaround to prevent a crash while looking at bug #687 */
296 :
297 13898634 : if (!str) {
298 0 : DEBUG(0,("talloc_sub_basic: NULL source string! This should not happen\n"));
299 0 : return NULL;
300 : }
301 :
302 13898634 : a_string = talloc_strdup(mem_ctx, str);
303 13898634 : if (a_string == NULL) {
304 0 : DEBUG(0, ("talloc_sub_basic: Out of memory!\n"));
305 0 : return NULL;
306 : }
307 :
308 13898634 : tmp_ctx = talloc_stackframe();
309 :
310 14137029 : for (s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) {
311 :
312 238395 : r = NULL;
313 238395 : b = a_string;
314 :
315 238395 : switch (*(p+1)) {
316 100388 : case 'U' :
317 100388 : r = strlower_talloc(tmp_ctx, smb_name);
318 100388 : if (r == NULL) {
319 0 : goto error;
320 : }
321 100388 : a_string = realloc_string_sub(a_string, "%U", r);
322 100388 : break;
323 52 : case 'G' : {
324 : struct passwd *pass;
325 52 : bool is_domain_name = false;
326 52 : const char *sep = lp_winbind_separator();
327 :
328 102 : if (domain_name != NULL && domain_name[0] != '\0' &&
329 50 : (lp_security() == SEC_ADS ||
330 0 : lp_security() == SEC_DOMAIN)) {
331 50 : r = talloc_asprintf(tmp_ctx,
332 : "%s%c%s",
333 : domain_name,
334 50 : *sep,
335 : smb_name);
336 50 : is_domain_name = true;
337 : } else {
338 2 : r = talloc_strdup(tmp_ctx, smb_name);
339 : }
340 52 : if (r == NULL) {
341 0 : goto error;
342 : }
343 :
344 52 : pass = Get_Pwnam_alloc(tmp_ctx, r);
345 52 : if (pass != NULL) {
346 : char *group_name;
347 :
348 28 : group_name = gidtoname(pass->pw_gid);
349 28 : if (is_domain_name) {
350 : char *group_sep;
351 28 : group_sep = strchr_m(group_name, *sep);
352 28 : if (group_sep != NULL) {
353 28 : group_name = group_sep + 1;
354 : }
355 : }
356 28 : a_string = realloc_string_sub(a_string,
357 : "%G",
358 : group_name);
359 : }
360 52 : TALLOC_FREE(pass);
361 52 : break;
362 : }
363 159 : case 'D' :
364 159 : r = strupper_talloc(tmp_ctx, domain_name);
365 159 : if (r == NULL) {
366 0 : goto error;
367 : }
368 159 : a_string = realloc_string_sub(a_string, "%D", r);
369 159 : break;
370 3 : case 'I' : {
371 3 : a_string = realloc_string_sub(
372 : a_string, "%I",
373 3 : sub_peeraddr[0] ? sub_peeraddr : "0.0.0.0");
374 3 : break;
375 : }
376 1 : case 'J' : {
377 1 : r = talloc_strdup(tmp_ctx,
378 1 : sub_peeraddr[0] ? sub_peeraddr : "0.0.0.0");
379 1 : make_address_pathsafe(r);
380 1 : a_string = realloc_string_sub(a_string, "%J", r);
381 1 : break;
382 : }
383 3 : case 'i':
384 3 : a_string = realloc_string_sub(
385 : a_string, "%i",
386 3 : sub_sockaddr[0] ? sub_sockaddr : "0.0.0.0");
387 3 : break;
388 1315 : case 'j' : {
389 1315 : r = talloc_strdup(tmp_ctx,
390 1315 : sub_sockaddr[0] ? sub_sockaddr : "0.0.0.0");
391 1315 : make_address_pathsafe(r);
392 1315 : a_string = realloc_string_sub(a_string, "%j", r);
393 1315 : break;
394 : }
395 6 : case 'L' :
396 6 : if ( strncasecmp_m(p, "%LOGONSERVER%", strlen("%LOGONSERVER%")) == 0 ) {
397 0 : break;
398 : }
399 6 : if (local_machine_name && *local_machine_name) {
400 6 : a_string = realloc_string_sub(a_string, "%L", local_machine_name);
401 : } else {
402 0 : a_string = realloc_string_sub(a_string, "%L", lp_netbios_name());
403 : }
404 6 : break;
405 94176 : case 'N' :
406 94176 : a_string = realloc_string_sub(a_string,
407 : "%N",
408 : lp_netbios_name());
409 94176 : break;
410 2 : case 'M' :
411 2 : a_string = realloc_string_sub(a_string, "%M",
412 2 : sub_peername ? sub_peername : "");
413 2 : break;
414 2 : case 'R' :
415 2 : a_string = realloc_string_sub(a_string, "%R", remote_proto);
416 2 : break;
417 2 : case 'T' :
418 2 : a_string = realloc_string_sub(a_string, "%T", current_timestring(tmp_ctx, False));
419 2 : break;
420 163 : case 't' :
421 163 : a_string = realloc_string_sub(a_string, "%t",
422 163 : current_minimal_timestring(tmp_ctx, False));
423 163 : break;
424 2 : case 'a' :
425 2 : a_string = realloc_string_sub(a_string, "%a",
426 : get_remote_arch_str());
427 2 : break;
428 2 : case 'd' :
429 2 : slprintf(pidstr,sizeof(pidstr)-1, "%d",(int)getpid());
430 2 : a_string = realloc_string_sub(a_string, "%d", pidstr);
431 2 : break;
432 2 : case 'h' :
433 2 : a_string = realloc_string_sub(a_string, "%h", myhostname());
434 2 : break;
435 40652 : case 'm' :
436 40652 : a_string = realloc_string_sub(a_string, "%m",
437 : remote_machine);
438 40652 : break;
439 2 : case 'v' :
440 2 : a_string = realloc_string_sub(a_string, "%v", samba_version_string());
441 2 : break;
442 2 : case 'w' :
443 2 : a_string = realloc_string_sub(a_string, "%w", lp_winbind_separator());
444 2 : break;
445 0 : case '$' :
446 0 : a_string = realloc_expand_env_var(a_string, p); /* Expand environment variables */
447 0 : break;
448 2 : case 'V' :
449 2 : slprintf(vnnstr,sizeof(vnnstr)-1, "%u", get_my_vnn());
450 2 : a_string = realloc_string_sub(a_string, "%V", vnnstr);
451 2 : break;
452 1459 : default:
453 1459 : break;
454 : }
455 :
456 238395 : p++;
457 238395 : TALLOC_FREE(r);
458 :
459 238395 : if (a_string == NULL) {
460 0 : goto done;
461 : }
462 : }
463 :
464 13840418 : goto done;
465 :
466 0 : error:
467 0 : TALLOC_FREE(a_string);
468 :
469 13048090 : done:
470 13898634 : TALLOC_FREE(tmp_ctx);
471 13840418 : return a_string;
472 : }
473 :
474 : /****************************************************************************
475 : Do some specific substitutions in a string.
476 : This function will return an allocated string that have to be freed.
477 : ****************************************************************************/
478 :
479 101229 : char *talloc_sub_specified(TALLOC_CTX *mem_ctx,
480 : const char *input_string,
481 : const char *username,
482 : const char *grpname,
483 : const char *domain,
484 : uid_t uid,
485 : gid_t gid)
486 : {
487 : char *a_string;
488 101229 : char *ret_string = NULL;
489 : char *b, *p, *s;
490 : TALLOC_CTX *tmp_ctx;
491 :
492 101229 : if (!(tmp_ctx = talloc_new(mem_ctx))) {
493 0 : DEBUG(0, ("talloc_new failed\n"));
494 0 : return NULL;
495 : }
496 :
497 101229 : a_string = talloc_strdup(tmp_ctx, input_string);
498 101229 : if (a_string == NULL) {
499 0 : DEBUG(0, ("talloc_sub_specified: Out of memory!\n"));
500 0 : goto done;
501 : }
502 :
503 203567 : for (s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) {
504 :
505 102347 : b = a_string;
506 :
507 102347 : switch (*(p+1)) {
508 50610 : case 'U' :
509 50610 : a_string = talloc_string_sub(
510 : tmp_ctx, a_string, "%U", username);
511 50610 : break;
512 2 : case 'u' :
513 2 : a_string = talloc_string_sub(
514 : tmp_ctx, a_string, "%u", username);
515 2 : break;
516 1120 : case 'G' :
517 1120 : if (gid != -1) {
518 : const char *name;
519 :
520 1119 : if (grpname != NULL) {
521 1118 : name = grpname;
522 : } else {
523 1 : name = gidtoname(gid);
524 : }
525 :
526 1119 : a_string = talloc_string_sub(tmp_ctx,
527 : a_string,
528 : "%G",
529 : name);
530 : } else {
531 1 : a_string = talloc_string_sub(
532 : tmp_ctx, a_string,
533 : "%G", "NO_GROUP");
534 : }
535 1118 : break;
536 2 : case 'g' :
537 2 : if (gid != -1) {
538 : const char *name;
539 :
540 1 : if (grpname != NULL) {
541 0 : name = grpname;
542 : } else {
543 1 : name = gidtoname(gid);
544 : }
545 :
546 1 : a_string = talloc_string_sub(tmp_ctx,
547 : a_string,
548 : "%g",
549 : name);
550 : } else {
551 1 : a_string = talloc_string_sub(
552 : tmp_ctx, a_string, "%g", "NO_GROUP");
553 : }
554 0 : break;
555 45329 : case 'D' :
556 45329 : a_string = talloc_string_sub(tmp_ctx, a_string,
557 : "%D", domain);
558 45329 : break;
559 5280 : case 'N' :
560 5280 : a_string = talloc_string_sub(tmp_ctx, a_string,
561 : "%N", lp_netbios_name());
562 5280 : break;
563 0 : default:
564 0 : break;
565 : }
566 :
567 102347 : p++;
568 102347 : if (a_string == NULL) {
569 0 : goto done;
570 : }
571 : }
572 :
573 : /* Watch out, using "mem_ctx" here, so all intermediate stuff goes
574 : * away with the TALLOC_FREE(tmp_ctx) further down. */
575 :
576 101229 : ret_string = talloc_sub_basic(mem_ctx, username, domain, a_string);
577 :
578 101229 : done:
579 101229 : TALLOC_FREE(tmp_ctx);
580 101229 : return ret_string;
581 : }
582 :
583 : /****************************************************************************
584 : ****************************************************************************/
585 :
586 62693 : char *talloc_sub_advanced(TALLOC_CTX *ctx,
587 : const char *servicename,
588 : const char *user,
589 : const char *connectpath,
590 : gid_t gid,
591 : const char *str)
592 : {
593 : char *a_string;
594 : char *b, *p, *s;
595 :
596 62693 : a_string = talloc_strdup(talloc_tos(), str);
597 62693 : if (a_string == NULL) {
598 0 : DEBUG(0, ("talloc_sub_advanced_only: Out of memory!\n"));
599 0 : return NULL;
600 : }
601 :
602 64196 : for (s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) {
603 :
604 2030 : b = a_string;
605 :
606 2030 : switch (*(p+1)) {
607 0 : case 'N':
608 0 : a_string = realloc_string_sub(a_string,
609 : "%N",
610 : lp_netbios_name());
611 0 : break;
612 0 : case 'H': {
613 : char *h;
614 0 : if ((h = get_user_home_dir(talloc_tos(), user)))
615 0 : a_string = realloc_string_sub(a_string, "%H", h);
616 0 : TALLOC_FREE(h);
617 0 : break;
618 : }
619 10 : case 'P':
620 10 : a_string = realloc_string_sub(a_string, "%P", connectpath);
621 10 : break;
622 0 : case 'S':
623 0 : a_string = realloc_string_sub(a_string, "%S", servicename);
624 0 : break;
625 2 : case 'g':
626 2 : a_string = realloc_string_sub(a_string, "%g", gidtoname(gid));
627 2 : break;
628 36 : case 'u':
629 36 : a_string = realloc_string_sub(a_string, "%u", user);
630 36 : break;
631 1982 : default:
632 1982 : break;
633 : }
634 :
635 2030 : p++;
636 2030 : if (a_string == NULL) {
637 0 : return NULL;
638 : }
639 : }
640 :
641 62166 : return a_string;
642 : }
643 :
644 61871 : char *talloc_sub_full(TALLOC_CTX *ctx,
645 : const char *servicename,
646 : const char *user,
647 : const char *connectpath,
648 : gid_t gid,
649 : const char *smb_name,
650 : const char *domain_name,
651 : const char *str)
652 : {
653 : char *a_string, *ret_string;
654 :
655 61871 : a_string = talloc_sub_advanced(ctx, servicename, user, connectpath,
656 : gid, str);
657 61871 : if (a_string == NULL) {
658 0 : return NULL;
659 : }
660 :
661 61871 : ret_string = talloc_sub_basic(ctx, smb_name, domain_name, a_string);
662 61871 : TALLOC_FREE(a_string);
663 61871 : return ret_string;
664 : }
|