1/* 2 Unix SMB/CIFS implementation. 3 Common popt routines 4 5 Copyright (C) Tim Potter 2001,2002 6 Copyright (C) Jelmer Vernooij 2002,2003 7 Copyright (C) James Peach 2006 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 3 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program. If not, see <http://www.gnu.org/licenses/>. 21*/ 22 23#include "includes.h" 24 25/* Handle command line options: 26 * -d,--debuglevel 27 * -s,--configfile 28 * -O,--socket-options 29 * -V,--version 30 * -l,--log-base 31 * -n,--netbios-name 32 * -W,--workgroup 33 * -i,--scope 34 */ 35 36extern bool AllowDebugChange; 37extern bool override_logfile; 38 39static void set_logfile(poptContext con, const char * arg) 40{ 41 42 char *lfile = NULL; 43 const char *pname; 44 45 /* Find out basename of current program */ 46 pname = strrchr_m(poptGetInvocationName(con),'/'); 47 48 if (!pname) 49 pname = poptGetInvocationName(con); 50 else 51 pname++; 52 53 if (asprintf(&lfile, "%s/log.%s", arg, pname) < 0) { 54 return; 55 } 56 lp_set_logfile(lfile); 57 SAFE_FREE(lfile); 58} 59 60static bool PrintSambaVersionString; 61 62static void popt_s3_talloc_log_fn(const char *message) 63{ 64 DEBUG(0,("%s", message)); 65} 66 67static void popt_common_callback(poptContext con, 68 enum poptCallbackReason reason, 69 const struct poptOption *opt, 70 const char *arg, const void *data) 71{ 72 73 if (reason == POPT_CALLBACK_REASON_PRE) { 74 set_logfile(con, get_dyn_LOGFILEBASE()); 75 talloc_set_log_fn(popt_s3_talloc_log_fn); 76 talloc_set_abort_fn(smb_panic); 77 return; 78 } 79 80 if (reason == POPT_CALLBACK_REASON_POST) { 81 82 if (PrintSambaVersionString) { 83 printf( "Version %s\n", samba_version_string()); 84 exit(0); 85 } 86 87 if (is_default_dyn_CONFIGFILE()) { 88 if(getenv("SMB_CONF_PATH")) { 89 set_dyn_CONFIGFILE(getenv("SMB_CONF_PATH")); 90 } 91 } 92 93 /* Further 'every Samba program must do this' hooks here. */ 94 return; 95 } 96 97 switch(opt->val) { 98 case 'd': 99 if (arg) { 100 debug_parse_levels(arg); 101 AllowDebugChange = False; 102 } 103 break; 104 105 case 'V': 106 PrintSambaVersionString = True; 107 break; 108 109 case 'O': 110 if (arg) { 111 lp_do_parameter(-1, "socket options", arg); 112 } 113 break; 114 115 case 's': 116 if (arg) { 117 set_dyn_CONFIGFILE(arg); 118 } 119 break; 120 121 case 'n': 122 if (arg) { 123 set_global_myname(arg); 124 } 125 break; 126 127 case 'l': 128 if (arg) { 129 set_logfile(con, arg); 130 override_logfile = True; 131 set_dyn_LOGFILEBASE(arg); 132 } 133 break; 134 135 case 'i': 136 if (arg) { 137 set_global_scope(arg); 138 } 139 break; 140 141 case 'W': 142 if (arg) { 143 set_global_myworkgroup(arg); 144 } 145 break; 146 } 147} 148 149struct poptOption popt_common_connection[] = { 150 { NULL, 0, POPT_ARG_CALLBACK, (void *)popt_common_callback }, 151 { "socket-options", 'O', POPT_ARG_STRING, NULL, 'O', "socket options to use", 152 "SOCKETOPTIONS" }, 153 { "netbiosname", 'n', POPT_ARG_STRING, NULL, 'n', "Primary netbios name", "NETBIOSNAME" }, 154 { "workgroup", 'W', POPT_ARG_STRING, NULL, 'W', "Set the workgroup name", "WORKGROUP" }, 155 { "scope", 'i', POPT_ARG_STRING, NULL, 'i', "Use this Netbios scope", "SCOPE" }, 156 157 POPT_TABLEEND 158}; 159 160struct poptOption popt_common_samba[] = { 161 { NULL, 0, POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST, (void *)popt_common_callback }, 162 { "debuglevel", 'd', POPT_ARG_STRING, NULL, 'd', "Set debug level", "DEBUGLEVEL" }, 163 { "configfile", 's', POPT_ARG_STRING, NULL, 's', "Use alternate configuration file", "CONFIGFILE" }, 164 { "log-basename", 'l', POPT_ARG_STRING, NULL, 'l', "Base name for log files", "LOGFILEBASE" }, 165 { "version", 'V', POPT_ARG_NONE, NULL, 'V', "Print version" }, 166 POPT_TABLEEND 167}; 168 169struct poptOption popt_common_configfile[] = { 170 { NULL, 0, POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST, (void *)popt_common_callback }, 171 { "configfile", 0, POPT_ARG_STRING, NULL, 's', "Use alternate configuration file", "CONFIGFILE" }, 172 POPT_TABLEEND 173}; 174 175struct poptOption popt_common_version[] = { 176 { NULL, 0, POPT_ARG_CALLBACK|POPT_CBFLAG_POST, (void *)popt_common_callback }, 177 { "version", 'V', POPT_ARG_NONE, NULL, 'V', "Print version" }, 178 POPT_TABLEEND 179}; 180 181struct poptOption popt_common_debuglevel[] = { 182 { NULL, 0, POPT_ARG_CALLBACK, (void *)popt_common_callback }, 183 { "debuglevel", 'd', POPT_ARG_STRING, NULL, 'd', "Set debug level", "DEBUGLEVEL" }, 184 POPT_TABLEEND 185}; 186 187 188/* Handle command line options: 189 * --sbindir 190 * --bindir 191 * --swatdir 192 * --lmhostsfile 193 * --libdir 194 * --modulesdir 195 * --shlibext 196 * --lockdir 197 * --statedir 198 * --cachedir 199 * --piddir 200 * --smb-passwd-file 201 * --private-dir 202 */ 203 204enum dyn_item{ 205 DYN_SBINDIR = 1, 206 DYN_BINDIR, 207 DYN_SWATDIR, 208 DYN_LMHOSTSFILE, 209 DYN_LIBDIR, 210 DYN_MODULESDIR, 211 DYN_SHLIBEXT, 212 DYN_LOCKDIR, 213 DYN_STATEDIR, 214 DYN_CACHEDIR, 215 DYN_PIDDIR, 216 DYN_SMB_PASSWD_FILE, 217 DYN_PRIVATE_DIR, 218}; 219 220 221static void popt_dynconfig_callback(poptContext con, 222 enum poptCallbackReason reason, 223 const struct poptOption *opt, 224 const char *arg, const void *data) 225{ 226 227 switch (opt->val) { 228 case DYN_SBINDIR: 229 if (arg) { 230 set_dyn_SBINDIR(arg); 231 } 232 break; 233 234 case DYN_BINDIR: 235 if (arg) { 236 set_dyn_BINDIR(arg); 237 } 238 break; 239 240 case DYN_SWATDIR: 241 if (arg) { 242 set_dyn_SWATDIR(arg); 243 } 244 break; 245 246 case DYN_LMHOSTSFILE: 247 if (arg) { 248 set_dyn_LMHOSTSFILE(arg); 249 } 250 break; 251 252 case DYN_LIBDIR: 253 if (arg) { 254 set_dyn_LIBDIR(arg); 255 } 256 break; 257 258 case DYN_MODULESDIR: 259 if (arg) { 260 set_dyn_MODULESDIR(arg); 261 } 262 break; 263 264 case DYN_SHLIBEXT: 265 if (arg) { 266 set_dyn_SHLIBEXT(arg); 267 } 268 break; 269 270 case DYN_LOCKDIR: 271 if (arg) { 272 set_dyn_LOCKDIR(arg); 273 } 274 break; 275 276 case DYN_STATEDIR: 277 if (arg) { 278 set_dyn_STATEDIR(arg); 279 } 280 break; 281 282 case DYN_CACHEDIR: 283 if (arg) { 284 set_dyn_CACHEDIR(arg); 285 } 286 break; 287 288 case DYN_PIDDIR: 289 if (arg) { 290 set_dyn_PIDDIR(arg); 291 } 292 break; 293 294 case DYN_SMB_PASSWD_FILE: 295 if (arg) { 296 set_dyn_SMB_PASSWD_FILE(arg); 297 } 298 break; 299 300 case DYN_PRIVATE_DIR: 301 if (arg) { 302 set_dyn_PRIVATE_DIR(arg); 303 } 304 break; 305 306 } 307} 308 309const struct poptOption popt_common_dynconfig[] = { 310 311 { NULL, '\0', POPT_ARG_CALLBACK, (void *)popt_dynconfig_callback }, 312 313 { "sbindir", '\0' , POPT_ARG_STRING, NULL, DYN_SBINDIR, 314 "Path to sbin directory", "SBINDIR" }, 315 { "bindir", '\0' , POPT_ARG_STRING, NULL, DYN_BINDIR, 316 "Path to bin directory", "BINDIR" }, 317 { "swatdir", '\0' , POPT_ARG_STRING, NULL, DYN_SWATDIR, 318 "Path to SWAT installation directory", "SWATDIR" }, 319 { "lmhostsfile", '\0' , POPT_ARG_STRING, NULL, DYN_LMHOSTSFILE, 320 "Path to lmhosts file", "LMHOSTSFILE" }, 321 { "libdir", '\0' , POPT_ARG_STRING, NULL, DYN_LIBDIR, 322 "Path to shared library directory", "LIBDIR" }, 323 { "modulesdir", '\0' , POPT_ARG_STRING, NULL, DYN_MODULESDIR, 324 "Path to shared modules directory", "MODULESDIR" }, 325 { "shlibext", '\0' , POPT_ARG_STRING, NULL, DYN_SHLIBEXT, 326 "Shared library extension", "SHLIBEXT" }, 327 { "lockdir", '\0' , POPT_ARG_STRING, NULL, DYN_LOCKDIR, 328 "Path to lock file directory", "LOCKDIR" }, 329 { "statedir", '\0' , POPT_ARG_STRING, NULL, DYN_STATEDIR, 330 "Path to persistent state file directory", "STATEDIR" }, 331 { "cachedir", '\0' , POPT_ARG_STRING, NULL, DYN_CACHEDIR, 332 "Path to temporary cache file directory", "CACHEDIR" }, 333 { "piddir", '\0' , POPT_ARG_STRING, NULL, DYN_PIDDIR, 334 "Path to PID file directory", "PIDDIR" }, 335 { "smb-passwd-file", '\0' , POPT_ARG_STRING, NULL, DYN_SMB_PASSWD_FILE, 336 "Path to smbpasswd file", "SMB_PASSWD_FILE" }, 337 { "private-dir", '\0' , POPT_ARG_STRING, NULL, DYN_PRIVATE_DIR, 338 "Path to private data directory", "PRIVATE_DIR" }, 339 340 POPT_TABLEEND 341}; 342 343/**************************************************************************** 344 * get a password from a a file or file descriptor 345 * exit on failure 346 * ****************************************************************************/ 347 348static void get_password_file(struct user_auth_info *auth_info) 349{ 350 int fd = -1; 351 char *p; 352 bool close_it = False; 353 char *spec = NULL; 354 char pass[128]; 355 356 if ((p = getenv("PASSWD_FD")) != NULL) { 357 if (asprintf(&spec, "descriptor %s", p) < 0) { 358 return; 359 } 360 sscanf(p, "%d", &fd); 361 close_it = false; 362 } else if ((p = getenv("PASSWD_FILE")) != NULL) { 363 fd = sys_open(p, O_RDONLY, 0); 364 spec = SMB_STRDUP(p); 365 if (fd < 0) { 366 fprintf(stderr, "Error opening PASSWD_FILE %s: %s\n", 367 spec, strerror(errno)); 368 exit(1); 369 } 370 close_it = True; 371 } 372 373 if (fd < 0) { 374 fprintf(stderr, "fd = %d, < 0\n", fd); 375 exit(1); 376 } 377 378 for(p = pass, *p = '\0'; /* ensure that pass is null-terminated */ 379 p && p - pass < sizeof(pass);) { 380 switch (read(fd, p, 1)) { 381 case 1: 382 if (*p != '\n' && *p != '\0') { 383 *++p = '\0'; /* advance p, and null-terminate pass */ 384 break; 385 } 386 case 0: 387 if (p - pass) { 388 *p = '\0'; /* null-terminate it, just in case... */ 389 p = NULL; /* then force the loop condition to become false */ 390 break; 391 } else { 392 fprintf(stderr, "Error reading password from file %s: %s\n", 393 spec, "empty password\n"); 394 SAFE_FREE(spec); 395 exit(1); 396 } 397 398 default: 399 fprintf(stderr, "Error reading password from file %s: %s\n", 400 spec, strerror(errno)); 401 SAFE_FREE(spec); 402 exit(1); 403 } 404 } 405 SAFE_FREE(spec); 406 407 set_cmdline_auth_info_password(auth_info, pass); 408 if (close_it) { 409 close(fd); 410 } 411} 412 413static void get_credentials_file(struct user_auth_info *auth_info, 414 const char *file) 415{ 416 XFILE *auth; 417 fstring buf; 418 uint16 len = 0; 419 char *ptr, *val, *param; 420 421 if ((auth=x_fopen(file, O_RDONLY, 0)) == NULL) 422 { 423 /* fail if we can't open the credentials file */ 424 d_printf("ERROR: Unable to open credentials file!\n"); 425 exit(-1); 426 } 427 428 while (!x_feof(auth)) 429 { 430 /* get a line from the file */ 431 if (!x_fgets(buf, sizeof(buf), auth)) 432 continue; 433 len = strlen(buf); 434 435 if ((len) && (buf[len-1]=='\n')) 436 { 437 buf[len-1] = '\0'; 438 len--; 439 } 440 if (len == 0) 441 continue; 442 443 /* break up the line into parameter & value. 444 * will need to eat a little whitespace possibly */ 445 param = buf; 446 if (!(ptr = strchr_m (buf, '='))) 447 continue; 448 449 val = ptr+1; 450 *ptr = '\0'; 451 452 /* eat leading white space */ 453 while ((*val!='\0') && ((*val==' ') || (*val=='\t'))) 454 val++; 455 456 if (strwicmp("password", param) == 0) { 457 set_cmdline_auth_info_password(auth_info, val); 458 } else if (strwicmp("username", param) == 0) { 459 set_cmdline_auth_info_username(auth_info, val); 460 } else if (strwicmp("domain", param) == 0) { 461 set_global_myworkgroup(val); 462 } 463 memset(buf, 0, sizeof(buf)); 464 } 465 x_fclose(auth); 466} 467 468/* Handle command line options: 469 * -U,--user 470 * -A,--authentication-file 471 * -k,--use-kerberos 472 * -N,--no-pass 473 * -S,--signing 474 * -P --machine-pass 475 * -e --encrypt 476 * -C --use-ccache 477 */ 478 479 480static void popt_common_credentials_callback(poptContext con, 481 enum poptCallbackReason reason, 482 const struct poptOption *opt, 483 const char *arg, const void *data) 484{ 485 struct user_auth_info *auth_info = talloc_get_type_abort( 486 *((const char **)data), struct user_auth_info); 487 char *p; 488 489 if (reason == POPT_CALLBACK_REASON_PRE) { 490 set_cmdline_auth_info_username(auth_info, "GUEST"); 491 492 if (getenv("LOGNAME")) { 493 set_cmdline_auth_info_username(auth_info, 494 getenv("LOGNAME")); 495 } 496 497 if (getenv("USER")) { 498 char *puser = SMB_STRDUP(getenv("USER")); 499 if (!puser) { 500 exit(ENOMEM); 501 } 502 set_cmdline_auth_info_username(auth_info, puser); 503 504 if ((p = strchr_m(puser,'%'))) { 505 size_t len; 506 *p = 0; 507 len = strlen(p+1); 508 set_cmdline_auth_info_password(auth_info, p+1); 509 memset(strchr_m(getenv("USER"),'%')+1,'X',len); 510 } 511 SAFE_FREE(puser); 512 } 513 514 if (getenv("PASSWD")) { 515 set_cmdline_auth_info_password(auth_info, 516 getenv("PASSWD")); 517 } 518 519 if (getenv("PASSWD_FD") || getenv("PASSWD_FILE")) { 520 get_password_file(auth_info); 521 } 522 523 return; 524 } 525 526 switch(opt->val) { 527 case 'U': 528 { 529 char *lp; 530 char *puser = SMB_STRDUP(arg); 531 532 if ((lp=strchr_m(puser,'%'))) { 533 size_t len; 534 *lp = 0; 535 set_cmdline_auth_info_username(auth_info, 536 puser); 537 set_cmdline_auth_info_password(auth_info, 538 lp+1); 539 len = strlen(lp+1); 540 memset(strchr_m(arg,'%')+1,'X',len); 541 } else { 542 set_cmdline_auth_info_username(auth_info, 543 puser); 544 } 545 SAFE_FREE(puser); 546 } 547 break; 548 549 case 'A': 550 get_credentials_file(auth_info, arg); 551 break; 552 553 case 'k': 554#ifndef HAVE_KRB5 555 d_printf("No kerberos support compiled in\n"); 556 exit(1); 557#else 558 set_cmdline_auth_info_use_krb5_ticket(auth_info); 559#endif 560 break; 561 562 case 'S': 563 if (!set_cmdline_auth_info_signing_state(auth_info, arg)) { 564 fprintf(stderr, "Unknown signing option %s\n", arg ); 565 exit(1); 566 } 567 break; 568 case 'P': 569 set_cmdline_auth_info_use_machine_account(auth_info); 570 break; 571 case 'N': 572 set_cmdline_auth_info_password(auth_info, ""); 573 break; 574 case 'e': 575 set_cmdline_auth_info_smb_encrypt(auth_info); 576 break; 577 case 'C': 578 set_cmdline_auth_info_use_ccache(auth_info, true); 579 break; 580 } 581} 582 583static struct user_auth_info *global_auth_info; 584 585void popt_common_set_auth_info(struct user_auth_info *auth_info) 586{ 587 global_auth_info = auth_info; 588} 589 590struct poptOption popt_common_credentials[] = { 591 { NULL, 0, POPT_ARG_CALLBACK|POPT_CBFLAG_PRE, 592 (void *)popt_common_credentials_callback, 0, 593 (const char *)&global_auth_info }, 594 { "user", 'U', POPT_ARG_STRING, NULL, 'U', "Set the network username", "USERNAME" }, 595 { "no-pass", 'N', POPT_ARG_NONE, NULL, 'N', "Don't ask for a password" }, 596 { "kerberos", 'k', POPT_ARG_NONE, NULL, 'k', "Use kerberos (active directory) authentication" }, 597 { "authentication-file", 'A', POPT_ARG_STRING, NULL, 'A', "Get the credentials from a file", "FILE" }, 598 { "signing", 'S', POPT_ARG_STRING, NULL, 'S', "Set the client signing state", "on|off|required" }, 599 {"machine-pass", 'P', POPT_ARG_NONE, NULL, 'P', "Use stored machine account password" }, 600 {"encrypt", 'e', POPT_ARG_NONE, NULL, 'e', "Encrypt SMB transport (UNIX extended servers only)" }, 601 {"use-ccache", 'C', POPT_ARG_NONE, NULL, 'C', 602 "Use the winbind ccache for authentication" }, 603 POPT_TABLEEND 604}; 605