1/* 2 Unix SMB/CIFS implementation. 3 string substitution functions 4 Copyright (C) Andrew Tridgell 1992-2000 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19*/ 20 21 22#include "includes.h" 23 24fstring local_machine=""; 25fstring remote_arch="UNKNOWN"; 26userdom_struct current_user_info; 27fstring remote_proto="UNKNOWN"; 28 29static fstring remote_machine; 30static fstring smb_user_name; 31 32/** 33 * Set the 'local' machine name 34 * @param local_name the name we are being called 35 * @param if this is the 'final' name for us, not be be changed again 36 */ 37 38void set_local_machine_name(const char* local_name, BOOL perm) 39{ 40 static BOOL already_perm = False; 41 fstring tmp_local_machine; 42 43 fstrcpy(tmp_local_machine,local_name); 44 trim_char(tmp_local_machine,' ',' '); 45 46 /* 47 * Windows NT/2k uses "*SMBSERVER" and XP uses "*SMBSERV" 48 * arrggg!!! 49 */ 50 51 if ( strequal(tmp_local_machine, "*SMBSERVER") || strequal(tmp_local_machine, "*SMBSERV") ) { 52 fstrcpy( local_machine, client_socket_addr() ); 53 return; 54 } 55 56 if (already_perm) 57 return; 58 59 already_perm = perm; 60 61 alpha_strcpy(local_machine,tmp_local_machine,SAFE_NETBIOS_CHARS,sizeof(local_machine)-1); 62 strlower_m(local_machine); 63} 64 65/** 66 * Set the 'remote' machine name 67 * @param remote_name the name our client wants to be called by 68 * @param if this is the 'final' name for them, not be be changed again 69 */ 70 71void set_remote_machine_name(const char* remote_name, BOOL perm) 72{ 73 static BOOL already_perm = False; 74 fstring tmp_remote_machine; 75 76 if (already_perm) 77 return; 78 79 already_perm = perm; 80 81 fstrcpy(tmp_remote_machine,remote_name); 82 trim_char(tmp_remote_machine,' ',' '); 83 alpha_strcpy(remote_machine,tmp_remote_machine,SAFE_NETBIOS_CHARS,sizeof(remote_machine)-1); 84 strlower_m(remote_machine); 85} 86 87const char* get_remote_machine_name(void) 88{ 89 return remote_machine; 90} 91 92const char* get_local_machine_name(void) 93{ 94 if (!*local_machine) { 95 return global_myname(); 96 } 97 98 return local_machine; 99} 100 101/******************************************************************* 102 Setup the string used by %U substitution. 103********************************************************************/ 104 105void sub_set_smb_name(const char *name) 106{ 107 fstring tmp; 108 109 /* don't let anonymous logins override the name */ 110 if (! *name) 111 return; 112 113 fstrcpy(tmp,name); 114 trim_char(tmp,' ',' '); 115 strlower_m(tmp); 116 alpha_strcpy(smb_user_name,tmp,SAFE_NETBIOS_CHARS,sizeof(smb_user_name)-1); 117} 118 119char* sub_get_smb_name( void ) 120{ 121 return smb_user_name; 122} 123 124/******************************************************************* 125 Setup the strings used by substitutions. Called per packet. Ensure 126 %U name is set correctly also. 127********************************************************************/ 128 129void set_current_user_info(const userdom_struct *pcui) 130{ 131 current_user_info = *pcui; 132 /* The following is safe as current_user_info.smb_name 133 * has already been sanitised in register_vuid. */ 134 fstrcpy(smb_user_name, current_user_info.smb_name); 135} 136 137/******************************************************************* 138 return the current active user name 139*******************************************************************/ 140 141const char* get_current_username( void ) 142{ 143 if ( current_user_info.smb_name[0] == '\0' ) 144 return smb_user_name; 145 146 return current_user_info.smb_name; 147} 148 149/******************************************************************* 150 Given a pointer to a %$(NAME) expand it as an environment variable. 151 Return the number of characters by which the pointer should be advanced. 152 Based on code by Branko Cibej <branko.cibej@hermes.si> 153 When this is called p points at the '%' character. 154********************************************************************/ 155 156static size_t expand_env_var(char *p, int len) 157{ 158 fstring envname; 159 char *envval; 160 char *q, *r; 161 int copylen; 162 163 if (p[1] != '$') 164 return 1; 165 166 if (p[2] != '(') 167 return 2; 168 169 /* 170 * Look for the terminating ')'. 171 */ 172 173 if ((q = strchr_m(p,')')) == NULL) { 174 DEBUG(0,("expand_env_var: Unterminated environment variable [%s]\n", p)); 175 return 2; 176 } 177 178 /* 179 * Extract the name from within the %$(NAME) string. 180 */ 181 182 r = p+3; 183 copylen = MIN((q-r),(sizeof(envname)-1)); 184 strncpy(envname,r,copylen); 185 envname[copylen] = '\0'; 186 187 if ((envval = getenv(envname)) == NULL) { 188 DEBUG(0,("expand_env_var: Environment variable [%s] not set\n", envname)); 189 return 2; 190 } 191 192 /* 193 * Copy the full %$(NAME) into envname so it 194 * can be replaced. 195 */ 196 197 copylen = MIN((q+1-p),(sizeof(envname)-1)); 198 strncpy(envname,p,copylen); 199 envname[copylen] = '\0'; 200 string_sub(p,envname,envval,len); 201 return 0; /* Allow the environment contents to be parsed. */ 202} 203 204/******************************************************************* 205 Given a pointer to a %$(NAME) in p and the whole string in str 206 expand it as an environment variable. 207 Return a new allocated and expanded string. 208 Based on code by Branko Cibej <branko.cibej@hermes.si> 209 When this is called p points at the '%' character. 210 May substitute multiple occurrencies of the same env var. 211********************************************************************/ 212 213 214static char * realloc_expand_env_var(char *str, char *p) 215{ 216 char *envname; 217 char *envval; 218 char *q, *r; 219 int copylen; 220 221 if (p[0] != '%' || p[1] != '$' || p[2] != '(') 222 return str; 223 224 /* 225 * Look for the terminating ')'. 226 */ 227 228 if ((q = strchr_m(p,')')) == NULL) { 229 DEBUG(0,("expand_env_var: Unterminated environment variable [%s]\n", p)); 230 return str; 231 } 232 233 /* 234 * Extract the name from within the %$(NAME) string. 235 */ 236 237 r = p + 3; 238 copylen = q - r; 239 envname = (char *)SMB_MALLOC(copylen + 1 + 4); /* reserve space for use later add %$() chars */ 240 if (envname == NULL) return NULL; 241 strncpy(envname,r,copylen); 242 envname[copylen] = '\0'; 243 244 if ((envval = getenv(envname)) == NULL) { 245 DEBUG(0,("expand_env_var: Environment variable [%s] not set\n", envname)); 246 SAFE_FREE(envname); 247 return str; 248 } 249 250 /* 251 * Copy the full %$(NAME) into envname so it 252 * can be replaced. 253 */ 254 255 copylen = q + 1 - p; 256 strncpy(envname,p,copylen); 257 envname[copylen] = '\0'; 258 r = realloc_string_sub(str, envname, envval); 259 SAFE_FREE(envname); 260 if (r == NULL) return NULL; 261 return r; 262} 263 264/******************************************************************* 265 Patch from jkf@soton.ac.uk 266 Added this to implement %p (NIS auto-map version of %H) 267*******************************************************************/ 268 269static char *automount_path(const char *user_name) 270{ 271 static pstring server_path; 272 273 /* use the passwd entry as the default */ 274 /* this will be the default if WITH_AUTOMOUNT is not used or fails */ 275 276 pstrcpy(server_path, get_user_home_dir(user_name)); 277 278#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT)) 279 280 if (lp_nis_home_map()) { 281 char *home_path_start; 282 char *automount_value = automount_lookup(user_name); 283 284 if(strlen(automount_value) > 0) { 285 home_path_start = strchr_m(automount_value,':'); 286 if (home_path_start != NULL) { 287 DEBUG(5, ("NIS lookup succeeded. Home path is: %s\n", 288 home_path_start?(home_path_start+1):"")); 289 pstrcpy(server_path, home_path_start+1); 290 } 291 } else { 292 /* NIS key lookup failed: default to user home directory from password file */ 293 DEBUG(5, ("NIS lookup failed. Using Home path from passwd file. Home path is: %s\n", server_path )); 294 } 295 } 296#endif 297 298 DEBUG(4,("Home server path: %s\n", server_path)); 299 300 return server_path; 301} 302 303/******************************************************************* 304 Patch from jkf@soton.ac.uk 305 This is Luke's original function with the NIS lookup code 306 moved out to a separate function. 307*******************************************************************/ 308 309static const char *automount_server(const char *user_name) 310{ 311 static pstring server_name; 312 const char *local_machine_name = get_local_machine_name(); 313 314 /* use the local machine name as the default */ 315 /* this will be the default if WITH_AUTOMOUNT is not used or fails */ 316 if (local_machine_name && *local_machine_name) 317 pstrcpy(server_name, local_machine_name); 318 else 319 pstrcpy(server_name, global_myname()); 320 321#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT)) 322 323 if (lp_nis_home_map()) { 324 int home_server_len; 325 char *automount_value = automount_lookup(user_name); 326 home_server_len = strcspn(automount_value,":"); 327 DEBUG(5, ("NIS lookup succeeded. Home server length: %d\n",home_server_len)); 328 if (home_server_len > sizeof(pstring)) 329 home_server_len = sizeof(pstring); 330 strncpy(server_name, automount_value, home_server_len); 331 server_name[home_server_len] = '\0'; 332 } 333#endif 334 335 DEBUG(4,("Home server: %s\n", server_name)); 336 337 return server_name; 338} 339 340/**************************************************************************** 341 Do some standard substitutions in a string. 342 len is the length in bytes of the space allowed in string str. If zero means 343 don't allow expansions. 344****************************************************************************/ 345 346void standard_sub_basic(const char *smb_name, char *str,size_t len) 347{ 348 char *p, *s; 349 fstring pidstr; 350 struct passwd *pass; 351 const char *local_machine_name = get_local_machine_name(); 352 353 for (s=str; (p=strchr_m(s, '%'));s=p) { 354 fstring tmp_str; 355 356 int l = (int)len - (int)(p-str); 357 358 if (l < 0) 359 l = 0; 360 361 switch (*(p+1)) { 362 case 'U' : 363 fstrcpy(tmp_str, smb_name); 364 strlower_m(tmp_str); 365 string_sub(p,"%U",tmp_str,l); 366 break; 367 case 'G' : 368 fstrcpy(tmp_str, smb_name); 369 if ((pass = Get_Pwnam(tmp_str))!=NULL) { 370 string_sub(p,"%G",gidtoname(pass->pw_gid),l); 371 } else { 372 p += 2; 373 } 374 break; 375 case 'D' : 376 fstrcpy(tmp_str, current_user_info.domain); 377 strupper_m(tmp_str); 378 string_sub(p,"%D", tmp_str,l); 379 break; 380 case 'I' : 381 string_sub(p,"%I", client_addr(),l); 382 break; 383 case 'i' : 384 string_sub(p,"%i", client_socket_addr(),l); 385 break; 386 case 'L' : 387 if (local_machine_name && *local_machine_name) 388 string_sub(p,"%L", local_machine_name,l); 389 else { 390 pstring temp_name; 391 392 pstrcpy(temp_name, global_myname()); 393 strlower_m(temp_name); 394 string_sub(p,"%L", temp_name,l); 395 } 396 break; 397 case 'M' : 398 string_sub(p,"%M", client_name(),l); 399 break; 400 case 'R' : 401 string_sub(p,"%R", remote_proto,l); 402 break; 403 case 'T' : 404 string_sub(p,"%T", timestring(False),l); 405 break; 406 case 'a' : 407 string_sub(p,"%a", remote_arch,l); 408 break; 409 case 'd' : 410 slprintf(pidstr,sizeof(pidstr)-1, "%d",(int)sys_getpid()); 411 string_sub(p,"%d", pidstr,l); 412 break; 413 case 'h' : 414 string_sub(p,"%h", myhostname(),l); 415 break; 416 case 'm' : 417 string_sub(p,"%m", get_remote_machine_name(),l); 418 break; 419 case 'v' : 420 string_sub(p,"%v", SAMBA_VERSION_STRING,l); 421 break; 422 case '$' : 423 p += expand_env_var(p,l); 424 break; /* Expand environment variables */ 425 case '\0': 426 p++; 427 break; /* don't run off the end of the string */ 428 429 default: p+=2; 430 break; 431 } 432 } 433} 434 435static void standard_sub_advanced(int snum, const char *user, 436 const char *connectpath, gid_t gid, 437 const char *smb_name, char *str, size_t len) 438{ 439 char *p, *s, *home; 440 441 for (s=str; (p=strchr_m(s, '%'));s=p) { 442 int l = (int)len - (int)(p-str); 443 444 if (l < 0) 445 l = 0; 446 447 switch (*(p+1)) { 448 case 'N' : 449 string_sub(p,"%N", automount_server(user),l); 450 break; 451 case 'H': 452 if ((home = get_user_home_dir(user))) 453 string_sub(p,"%H",home, l); 454 else 455 p += 2; 456 break; 457 case 'P': 458 string_sub(p,"%P", connectpath, l); 459 break; 460 case 'S': 461 if ( snum != -1 ) 462 string_sub(p,"%S", lp_servicename(snum), l); 463 break; 464 case 'g': 465 string_sub(p,"%g", gidtoname(gid), l); 466 break; 467 case 'u': 468 string_sub(p,"%u", user, l); 469 break; 470 471 /* Patch from jkf@soton.ac.uk Left the %N (NIS 472 * server name) in standard_sub_basic as it is 473 * a feature for logon servers, hence uses the 474 * username. The %p (NIS server path) code is 475 * here as it is used instead of the default 476 * "path =" string in [homes] and so needs the 477 * service name, not the username. */ 478 case 'p': 479 if ( snum != -1 ) 480 string_sub(p,"%p", automount_path(lp_servicename(snum)), l); 481 break; 482 case '\0': 483 p++; 484 break; /* don't run off the end of the string */ 485 486 default: p+=2; 487 break; 488 } 489 } 490 491 standard_sub_basic(smb_name, str, len); 492} 493 494/**************************************************************************** 495 Do some standard substitutions in a string. 496 This function will return an allocated string that have to be freed. 497****************************************************************************/ 498 499char *talloc_sub_basic(TALLOC_CTX *mem_ctx, const char *smb_name, const char *str) 500{ 501 char *a, *t; 502 a = alloc_sub_basic(smb_name, str); 503 if (!a) return NULL; 504 t = talloc_strdup(mem_ctx, a); 505 SAFE_FREE(a); 506 return t; 507} 508 509char *alloc_sub_basic(const char *smb_name, const char *str) 510{ 511 char *b, *p, *s, *t, *r, *a_string; 512 fstring pidstr; 513 struct passwd *pass; 514 const char *local_machine_name = get_local_machine_name(); 515 516 /* workaround to prevent a crash while lookinf at bug #687 */ 517 518 if ( !str ) { 519 DEBUG(0,("alloc_sub_basic: NULL source string! This should not happen\n")); 520 return NULL; 521 } 522 523 a_string = SMB_STRDUP(str); 524 if (a_string == NULL) { 525 DEBUG(0, ("alloc_sub_specified: Out of memory!\n")); 526 return NULL; 527 } 528 529 for (b = s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) { 530 531 r = NULL; 532 b = t = a_string; 533 534 switch (*(p+1)) { 535 case 'U' : 536 r = strdup_lower(smb_name); 537 if (r == NULL) goto error; 538 t = realloc_string_sub(t, "%U", r); 539 break; 540 case 'G' : 541 r = SMB_STRDUP(smb_name); 542 if (r == NULL) goto error; 543 if ((pass = Get_Pwnam(r))!=NULL) { 544 t = realloc_string_sub(t, "%G", gidtoname(pass->pw_gid)); 545 } 546 break; 547 case 'D' : 548 r = strdup_upper(current_user_info.domain); 549 if (r == NULL) goto error; 550 t = realloc_string_sub(t, "%D", r); 551 break; 552 case 'I' : 553 t = realloc_string_sub(t, "%I", client_addr()); 554 break; 555 case 'L' : 556 if (local_machine_name && *local_machine_name) 557 t = realloc_string_sub(t, "%L", local_machine_name); 558 else 559 t = realloc_string_sub(t, "%L", global_myname()); 560 break; 561 case 'N': 562 t = realloc_string_sub(t, "%N", automount_server(smb_name)); 563 break; 564 case 'M' : 565 t = realloc_string_sub(t, "%M", client_name()); 566 break; 567 case 'R' : 568 t = realloc_string_sub(t, "%R", remote_proto); 569 break; 570 case 'T' : 571 t = realloc_string_sub(t, "%T", timestring(False)); 572 break; 573 case 'a' : 574 t = realloc_string_sub(t, "%a", remote_arch); 575 break; 576 case 'd' : 577 slprintf(pidstr,sizeof(pidstr)-1, "%d",(int)sys_getpid()); 578 t = realloc_string_sub(t, "%d", pidstr); 579 break; 580 case 'h' : 581 t = realloc_string_sub(t, "%h", myhostname()); 582 break; 583 case 'm' : 584 t = realloc_string_sub(t, "%m", remote_machine); 585 break; 586 case 'v' : 587 t = realloc_string_sub(t, "%v", SAMBA_VERSION_STRING); 588 break; 589 case '$' : 590 t = realloc_expand_env_var(t, p); /* Expand environment variables */ 591 break; 592 593 default: 594 break; 595 } 596 597 p++; 598 SAFE_FREE(r); 599 if (t == NULL) goto error; 600 a_string = t; 601 } 602 603 return a_string; 604error: 605 SAFE_FREE(a_string); 606 return NULL; 607} 608 609/**************************************************************************** 610 Do some specific substitutions in a string. 611 This function will return an allocated string that have to be freed. 612****************************************************************************/ 613 614char *talloc_sub_specified(TALLOC_CTX *mem_ctx, 615 const char *input_string, 616 const char *username, 617 const char *domain, 618 uid_t uid, 619 gid_t gid) 620{ 621 char *a, *t; 622 a = alloc_sub_specified(input_string, username, domain, uid, gid); 623 if (!a) return NULL; 624 t = talloc_strdup(mem_ctx, a); 625 SAFE_FREE(a); 626 return t; 627} 628 629char *alloc_sub_specified(const char *input_string, 630 const char *username, 631 const char *domain, 632 uid_t uid, 633 gid_t gid) 634{ 635 char *a_string, *ret_string; 636 char *b, *p, *s, *t; 637 638 a_string = SMB_STRDUP(input_string); 639 if (a_string == NULL) { 640 DEBUG(0, ("alloc_sub_specified: Out of memory!\n")); 641 return NULL; 642 } 643 644 for (b = s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) { 645 646 b = t = a_string; 647 648 switch (*(p+1)) { 649 case 'U' : 650 t = realloc_string_sub(t, "%U", username); 651 break; 652 case 'u' : 653 t = realloc_string_sub(t, "%u", username); 654 break; 655 case 'G' : 656 if (gid != -1) { 657 t = realloc_string_sub(t, "%G", gidtoname(gid)); 658 } else { 659 t = realloc_string_sub(t, "%G", "NO_GROUP"); 660 } 661 break; 662 case 'g' : 663 if (gid != -1) { 664 t = realloc_string_sub(t, "%g", gidtoname(gid)); 665 } else { 666 t = realloc_string_sub(t, "%g", "NO_GROUP"); 667 } 668 break; 669 case 'D' : 670 t = realloc_string_sub(t, "%D", domain); 671 break; 672 case 'N' : 673 t = realloc_string_sub(t, "%N", automount_server(username)); 674 break; 675 default: 676 break; 677 } 678 679 p++; 680 if (t == NULL) { 681 SAFE_FREE(a_string); 682 return NULL; 683 } 684 a_string = t; 685 } 686 687 ret_string = alloc_sub_basic(username, a_string); 688 SAFE_FREE(a_string); 689 return ret_string; 690} 691 692char *talloc_sub_advanced(TALLOC_CTX *mem_ctx, 693 int snum, 694 const char *user, 695 const char *connectpath, 696 gid_t gid, 697 const char *smb_name, 698 const char *str) 699{ 700 char *a, *t; 701 a = alloc_sub_advanced(snum, user, connectpath, gid, smb_name, str); 702 if (!a) return NULL; 703 t = talloc_strdup(mem_ctx, a); 704 SAFE_FREE(a); 705 return t; 706} 707 708char *alloc_sub_advanced(int snum, const char *user, 709 const char *connectpath, gid_t gid, 710 const char *smb_name, const char *str) 711{ 712 char *a_string, *ret_string; 713 char *b, *p, *s, *t, *h; 714 715 a_string = SMB_STRDUP(str); 716 if (a_string == NULL) { 717 DEBUG(0, ("alloc_sub_specified: Out of memory!\n")); 718 return NULL; 719 } 720 721 for (b = s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) { 722 723 b = t = a_string; 724 725 switch (*(p+1)) { 726 case 'N' : 727 t = realloc_string_sub(t, "%N", automount_server(user)); 728 break; 729 case 'H': 730 if ((h = get_user_home_dir(user))) 731 t = realloc_string_sub(t, "%H", h); 732 break; 733 case 'P': 734 t = realloc_string_sub(t, "%P", connectpath); 735 break; 736 case 'S': 737 t = realloc_string_sub(t, "%S", lp_servicename(snum)); 738 break; 739 case 'g': 740 t = realloc_string_sub(t, "%g", gidtoname(gid)); 741 break; 742 case 'u': 743 t = realloc_string_sub(t, "%u", user); 744 break; 745 746 /* Patch from jkf@soton.ac.uk Left the %N (NIS 747 * server name) in standard_sub_basic as it is 748 * a feature for logon servers, hence uses the 749 * username. The %p (NIS server path) code is 750 * here as it is used instead of the default 751 * "path =" string in [homes] and so needs the 752 * service name, not the username. */ 753 case 'p': 754 t = realloc_string_sub(t, "%p", automount_path(lp_servicename(snum))); 755 break; 756 757 default: 758 break; 759 } 760 761 p++; 762 if (t == NULL) { 763 SAFE_FREE(a_string); 764 return NULL; 765 } 766 a_string = t; 767 } 768 769 ret_string = alloc_sub_basic(smb_name, a_string); 770 SAFE_FREE(a_string); 771 return ret_string; 772} 773 774/**************************************************************************** 775 Do some standard substitutions in a string. 776****************************************************************************/ 777 778void standard_sub_conn(connection_struct *conn, char *str, size_t len) 779{ 780 standard_sub_advanced(SNUM(conn), conn->user, conn->connectpath, 781 conn->gid, smb_user_name, str, len); 782} 783 784char *talloc_sub_conn(TALLOC_CTX *mem_ctx, connection_struct *conn, const char *str) 785{ 786 return talloc_sub_advanced(mem_ctx, SNUM(conn), conn->user, 787 conn->connectpath, conn->gid, 788 smb_user_name, str); 789} 790 791char *alloc_sub_conn(connection_struct *conn, const char *str) 792{ 793 return alloc_sub_advanced(SNUM(conn), conn->user, conn->connectpath, 794 conn->gid, smb_user_name, str); 795} 796 797/**************************************************************************** 798 Like standard_sub but by snum. 799****************************************************************************/ 800 801void standard_sub_snum(int snum, char *str, size_t len) 802{ 803 extern struct current_user current_user; 804 static uid_t cached_uid = -1; 805 static fstring cached_user; 806 /* calling uidtoname() on every substitute would be too expensive, so 807 we cache the result here as nearly every call is for the same uid */ 808 809 if (cached_uid != current_user.uid) { 810 fstrcpy(cached_user, uidtoname(current_user.uid)); 811 cached_uid = current_user.uid; 812 } 813 814 standard_sub_advanced(snum, cached_user, "", current_user.gid, 815 smb_user_name, str, len); 816} 817