1/* 2 Unix SMB/CIFS implementation. 3 4 Winbind status program. 5 6 Copyright (C) Tim Potter 2000-2003 7 Copyright (C) Andrew Bartlett 2002 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 2 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, write to the Free Software 21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22*/ 23 24#include "includes.h" 25#include "winbindd.h" 26#include "debug.h" 27 28#undef DBGC_CLASS 29#define DBGC_CLASS DBGC_WINBIND 30 31extern int winbindd_fd; 32 33static char winbind_separator_int(BOOL strict) 34{ 35 struct winbindd_response response; 36 static BOOL got_sep; 37 static char sep; 38 39 if (got_sep) 40 return sep; 41 42 ZERO_STRUCT(response); 43 44 /* Send off request */ 45 46 if (winbindd_request_response(WINBINDD_INFO, NULL, &response) != 47 NSS_STATUS_SUCCESS) { 48 d_fprintf(stderr, "could not obtain winbind separator!\n"); 49 if (strict) { 50 return 0; 51 } 52 /* HACK: (this module should not call lp_ funtions) */ 53 return *lp_winbind_separator(); 54 } 55 56 sep = response.data.info.winbind_separator; 57 got_sep = True; 58 59 if (!sep) { 60 d_fprintf(stderr, "winbind separator was NULL!\n"); 61 if (strict) { 62 return 0; 63 } 64 /* HACK: (this module should not call lp_ funtions) */ 65 sep = *lp_winbind_separator(); 66 } 67 68 return sep; 69} 70 71static char winbind_separator(void) 72{ 73 return winbind_separator_int(False); 74} 75 76static const char *get_winbind_domain(void) 77{ 78 struct winbindd_response response; 79 static fstring winbind_domain; 80 81 ZERO_STRUCT(response); 82 83 /* Send off request */ 84 85 if (winbindd_request_response(WINBINDD_DOMAIN_NAME, NULL, &response) != 86 NSS_STATUS_SUCCESS) { 87 d_fprintf(stderr, "could not obtain winbind domain name!\n"); 88 89 /* HACK: (this module should not call lp_ funtions) */ 90 return lp_workgroup(); 91 } 92 93 fstrcpy(winbind_domain, response.data.domain_name); 94 95 return winbind_domain; 96 97} 98 99/* Copy of parse_domain_user from winbindd_util.c. Parse a string of the 100 form DOMAIN/user into a domain and a user */ 101 102static BOOL parse_wbinfo_domain_user(const char *domuser, fstring domain, 103 fstring user) 104{ 105 106 char *p = strchr(domuser,winbind_separator()); 107 108 if (!p) { 109 fstrcpy(user, domuser); 110 fstrcpy(domain, get_winbind_domain()); 111 return True; 112 } 113 114 fstrcpy(user, p+1); 115 fstrcpy(domain, domuser); 116 domain[PTR_DIFF(p, domuser)] = 0; 117 strupper_m(domain); 118 119 return True; 120} 121 122/* pull pwent info for a given user */ 123 124static BOOL wbinfo_get_userinfo(char *user) 125{ 126 struct winbindd_request request; 127 struct winbindd_response response; 128 NSS_STATUS result; 129 130 ZERO_STRUCT(request); 131 ZERO_STRUCT(response); 132 133 /* Send request */ 134 135 fstrcpy(request.data.username, user); 136 137 result = winbindd_request_response(WINBINDD_GETPWNAM, &request, &response); 138 139 if (result != NSS_STATUS_SUCCESS) 140 return False; 141 142 d_printf( "%s:%s:%d:%d:%s:%s:%s\n", 143 response.data.pw.pw_name, 144 response.data.pw.pw_passwd, 145 response.data.pw.pw_uid, 146 response.data.pw.pw_gid, 147 response.data.pw.pw_gecos, 148 response.data.pw.pw_dir, 149 response.data.pw.pw_shell ); 150 151 return True; 152} 153 154/* pull grent for a given group */ 155static BOOL wbinfo_get_groupinfo(char *group) 156{ 157 struct winbindd_request request; 158 struct winbindd_response response; 159 NSS_STATUS result; 160 161 ZERO_STRUCT(request); 162 ZERO_STRUCT(response); 163 164 /* Send request */ 165 166 fstrcpy(request.data.groupname, group); 167 168 result = winbindd_request_response(WINBINDD_GETGRNAM, &request, 169 &response); 170 171 if ( result != NSS_STATUS_SUCCESS) 172 return False; 173 174 d_printf( "%s:%s:%d\n", 175 response.data.gr.gr_name, 176 response.data.gr.gr_passwd, 177 response.data.gr.gr_gid ); 178 179 return True; 180} 181 182/* List groups a user is a member of */ 183 184static BOOL wbinfo_get_usergroups(char *user) 185{ 186 struct winbindd_request request; 187 struct winbindd_response response; 188 NSS_STATUS result; 189 int i; 190 191 ZERO_STRUCT(request); 192 ZERO_STRUCT(response); 193 194 /* Send request */ 195 196 fstrcpy(request.data.username, user); 197 198 result = winbindd_request_response(WINBINDD_GETGROUPS, &request, &response); 199 200 if (result != NSS_STATUS_SUCCESS) 201 return False; 202 203 for (i = 0; i < response.data.num_entries; i++) 204 d_printf("%d\n", (int)((gid_t *)response.extra_data.data)[i]); 205 206 SAFE_FREE(response.extra_data.data); 207 208 return True; 209} 210 211 212/* List group SIDs a user SID is a member of */ 213static BOOL wbinfo_get_usersids(char *user_sid) 214{ 215 struct winbindd_request request; 216 struct winbindd_response response; 217 NSS_STATUS result; 218 int i; 219 const char *s; 220 221 ZERO_STRUCT(request); 222 ZERO_STRUCT(response); 223 224 /* Send request */ 225 fstrcpy(request.data.sid, user_sid); 226 227 result = winbindd_request_response(WINBINDD_GETUSERSIDS, &request, &response); 228 229 if (result != NSS_STATUS_SUCCESS) 230 return False; 231 232 s = (const char *)response.extra_data.data; 233 for (i = 0; i < response.data.num_entries; i++) { 234 d_printf("%s\n", s); 235 s += strlen(s) + 1; 236 } 237 238 SAFE_FREE(response.extra_data.data); 239 240 return True; 241} 242 243static BOOL wbinfo_get_userdomgroups(const char *user_sid) 244{ 245 struct winbindd_request request; 246 struct winbindd_response response; 247 NSS_STATUS result; 248 249 ZERO_STRUCT(request); 250 ZERO_STRUCT(response); 251 252 /* Send request */ 253 fstrcpy(request.data.sid, user_sid); 254 255 result = winbindd_request_response(WINBINDD_GETUSERDOMGROUPS, &request, 256 &response); 257 258 if (result != NSS_STATUS_SUCCESS) 259 return False; 260 261 if (response.data.num_entries != 0) 262 printf("%s", (char *)response.extra_data.data); 263 264 SAFE_FREE(response.extra_data.data); 265 266 return True; 267} 268 269/* Convert NetBIOS name to IP */ 270 271static BOOL wbinfo_wins_byname(char *name) 272{ 273 struct winbindd_request request; 274 struct winbindd_response response; 275 276 ZERO_STRUCT(request); 277 ZERO_STRUCT(response); 278 279 /* Send request */ 280 281 fstrcpy(request.data.winsreq, name); 282 283 if (winbindd_request_response(WINBINDD_WINS_BYNAME, &request, &response) != 284 NSS_STATUS_SUCCESS) { 285 return False; 286 } 287 288 /* Display response */ 289 290 d_printf("%s\n", response.data.winsresp); 291 292 return True; 293} 294 295/* Convert IP to NetBIOS name */ 296 297static BOOL wbinfo_wins_byip(char *ip) 298{ 299 struct winbindd_request request; 300 struct winbindd_response response; 301 302 ZERO_STRUCT(request); 303 ZERO_STRUCT(response); 304 305 /* Send request */ 306 307 fstrcpy(request.data.winsreq, ip); 308 309 if (winbindd_request_response(WINBINDD_WINS_BYIP, &request, &response) != 310 NSS_STATUS_SUCCESS) { 311 return False; 312 } 313 314 /* Display response */ 315 316 d_printf("%s\n", response.data.winsresp); 317 318 return True; 319} 320 321/* List trusted domains */ 322 323static BOOL wbinfo_list_domains(BOOL list_all_domains) 324{ 325 struct winbindd_request request; 326 struct winbindd_response response; 327 328 ZERO_STRUCT(request); 329 ZERO_STRUCT(response); 330 331 /* Send request */ 332 333 request.data.list_all_domains = list_all_domains; 334 335 if (winbindd_request_response(WINBINDD_LIST_TRUSTDOM, &request, &response) != 336 NSS_STATUS_SUCCESS) 337 return False; 338 339 /* Display response */ 340 341 if (response.extra_data.data) { 342 const char *extra_data = (char *)response.extra_data.data; 343 fstring name; 344 char *p; 345 346 while(next_token(&extra_data, name, "\n", sizeof(fstring))) { 347 p = strchr(name, '\\'); 348 if (p == 0) { 349 d_fprintf(stderr, "Got invalid response: %s\n", 350 extra_data); 351 return False; 352 } 353 *p = 0; 354 d_printf("%s\n", name); 355 } 356 357 SAFE_FREE(response.extra_data.data); 358 } 359 360 return True; 361} 362 363/* List own domain */ 364 365static BOOL wbinfo_list_own_domain(void) 366{ 367 d_printf("%s\n", get_winbind_domain()); 368 369 return True; 370} 371 372/* show sequence numbers */ 373static BOOL wbinfo_show_sequence(const char *domain) 374{ 375 struct winbindd_request request; 376 struct winbindd_response response; 377 378 ZERO_STRUCT(response); 379 ZERO_STRUCT(request); 380 381 if ( domain ) 382 fstrcpy( request.domain_name, domain ); 383 384 /* Send request */ 385 386 if (winbindd_request_response(WINBINDD_SHOW_SEQUENCE, &request, &response) != 387 NSS_STATUS_SUCCESS) 388 return False; 389 390 /* Display response */ 391 392 if (response.extra_data.data) { 393 char *extra_data = (char *)response.extra_data.data; 394 d_printf("%s", extra_data); 395 SAFE_FREE(response.extra_data.data); 396 } 397 398 return True; 399} 400 401/* Show domain info */ 402 403static BOOL wbinfo_domain_info(const char *domain_name) 404{ 405 struct winbindd_request request; 406 struct winbindd_response response; 407 408 ZERO_STRUCT(request); 409 ZERO_STRUCT(response); 410 411 if ((strequal(domain_name, ".")) || (domain_name[0] == '\0')) 412 fstrcpy(request.domain_name, get_winbind_domain()); 413 else 414 fstrcpy(request.domain_name, domain_name); 415 416 /* Send request */ 417 418 if (winbindd_request_response(WINBINDD_DOMAIN_INFO, &request, &response) != 419 NSS_STATUS_SUCCESS) 420 return False; 421 422 /* Display response */ 423 424 d_printf("Name : %s\n", response.data.domain_info.name); 425 d_printf("Alt_Name : %s\n", response.data.domain_info.alt_name); 426 427 d_printf("SID : %s\n", response.data.domain_info.sid); 428 429 d_printf("Active Directory : %s\n", 430 response.data.domain_info.active_directory ? "Yes" : "No"); 431 d_printf("Native : %s\n", 432 response.data.domain_info.native_mode ? "Yes" : "No"); 433 434 d_printf("Primary : %s\n", 435 response.data.domain_info.primary ? "Yes" : "No"); 436 437 d_printf("Sequence : %d\n", response.data.domain_info.sequence_number); 438 439 return True; 440} 441 442/* Get a foreign DC's name */ 443static BOOL wbinfo_getdcname(const char *domain_name) 444{ 445 struct winbindd_request request; 446 struct winbindd_response response; 447 448 ZERO_STRUCT(request); 449 ZERO_STRUCT(response); 450 451 fstrcpy(request.domain_name, domain_name); 452 453 /* Send request */ 454 455 if (winbindd_request_response(WINBINDD_GETDCNAME, &request, &response) != 456 NSS_STATUS_SUCCESS) { 457 d_fprintf(stderr, "Could not get dc name for %s\n", domain_name); 458 return False; 459 } 460 461 /* Display response */ 462 463 d_printf("%s\n", response.data.dc_name); 464 465 return True; 466} 467 468/* Check trust account password */ 469 470static BOOL wbinfo_check_secret(void) 471{ 472 struct winbindd_response response; 473 NSS_STATUS result; 474 475 ZERO_STRUCT(response); 476 477 result = winbindd_request_response(WINBINDD_CHECK_MACHACC, NULL, &response); 478 479 d_printf("checking the trust secret via RPC calls %s\n", 480 (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed"); 481 482 if (result != NSS_STATUS_SUCCESS) 483 d_fprintf(stderr, "error code was %s (0x%x)\n", 484 response.data.auth.nt_status_string, 485 response.data.auth.nt_status); 486 487 return result == NSS_STATUS_SUCCESS; 488} 489 490/* Convert uid to sid */ 491 492static BOOL wbinfo_uid_to_sid(uid_t uid) 493{ 494 struct winbindd_request request; 495 struct winbindd_response response; 496 497 ZERO_STRUCT(request); 498 ZERO_STRUCT(response); 499 500 /* Send request */ 501 502 request.data.uid = uid; 503 504 if (winbindd_request_response(WINBINDD_UID_TO_SID, &request, &response) != 505 NSS_STATUS_SUCCESS) 506 return False; 507 508 /* Display response */ 509 510 d_printf("%s\n", response.data.sid.sid); 511 512 return True; 513} 514 515/* Convert gid to sid */ 516 517static BOOL wbinfo_gid_to_sid(gid_t gid) 518{ 519 struct winbindd_request request; 520 struct winbindd_response response; 521 522 ZERO_STRUCT(request); 523 ZERO_STRUCT(response); 524 525 /* Send request */ 526 527 request.data.gid = gid; 528 529 if (winbindd_request_response(WINBINDD_GID_TO_SID, &request, &response) != 530 NSS_STATUS_SUCCESS) 531 return False; 532 533 /* Display response */ 534 535 d_printf("%s\n", response.data.sid.sid); 536 537 return True; 538} 539 540/* Convert sid to uid */ 541 542static BOOL wbinfo_sid_to_uid(char *sid) 543{ 544 struct winbindd_request request; 545 struct winbindd_response response; 546 547 ZERO_STRUCT(request); 548 ZERO_STRUCT(response); 549 550 /* Send request */ 551 552 fstrcpy(request.data.sid, sid); 553 554 if (winbindd_request_response(WINBINDD_SID_TO_UID, &request, &response) != 555 NSS_STATUS_SUCCESS) 556 return False; 557 558 /* Display response */ 559 560 d_printf("%d\n", (int)response.data.uid); 561 562 return True; 563} 564 565static BOOL wbinfo_sid_to_gid(char *sid) 566{ 567 struct winbindd_request request; 568 struct winbindd_response response; 569 570 ZERO_STRUCT(request); 571 ZERO_STRUCT(response); 572 573 /* Send request */ 574 575 fstrcpy(request.data.sid, sid); 576 577 if (winbindd_request_response(WINBINDD_SID_TO_GID, &request, &response) != 578 NSS_STATUS_SUCCESS) 579 return False; 580 581 /* Display response */ 582 583 d_printf("%d\n", (int)response.data.gid); 584 585 return True; 586} 587 588static BOOL wbinfo_allocate_uid(void) 589{ 590 uid_t uid; 591 592 if (!winbind_allocate_uid(&uid)) 593 return False; 594 595 d_printf("New uid: %d\n", uid); 596 597 return True; 598} 599 600static BOOL wbinfo_allocate_gid(void) 601{ 602 gid_t gid; 603 604 if (!winbind_allocate_gid(&gid)) 605 return False; 606 607 d_printf("New gid: %d\n", gid); 608 609 return True; 610} 611 612/* Convert sid to string */ 613 614static BOOL wbinfo_lookupsid(char *sid) 615{ 616 struct winbindd_request request; 617 struct winbindd_response response; 618 619 ZERO_STRUCT(request); 620 ZERO_STRUCT(response); 621 622 /* Send off request */ 623 624 fstrcpy(request.data.sid, sid); 625 626 if (winbindd_request_response(WINBINDD_LOOKUPSID, &request, &response) != 627 NSS_STATUS_SUCCESS) 628 return False; 629 630 /* Display response */ 631 632 d_printf("%s%c%s %d\n", response.data.name.dom_name, 633 winbind_separator(), response.data.name.name, 634 response.data.name.type); 635 636 return True; 637} 638 639/* Lookup a list of RIDs */ 640 641static BOOL wbinfo_lookuprids(char *domain, char *arg) 642{ 643 size_t i; 644 DOM_SID sid; 645 int num_rids; 646 uint32 *rids; 647 const char *p; 648 char ridstr[32]; 649 const char **names; 650 enum lsa_SidType *types; 651 const char *domain_name; 652 TALLOC_CTX *mem_ctx; 653 struct winbindd_request request; 654 struct winbindd_response response; 655 656 ZERO_STRUCT(request); 657 ZERO_STRUCT(response); 658 659 if ((domain == NULL) || (strequal(domain, ".")) || (domain[0] == '\0')) 660 fstrcpy(request.domain_name, get_winbind_domain()); 661 else 662 fstrcpy(request.domain_name, domain); 663 664 /* Send request */ 665 666 if (winbindd_request_response(WINBINDD_DOMAIN_INFO, &request, &response) != 667 NSS_STATUS_SUCCESS) { 668 d_printf("Could not get domain sid for %s\n", request.domain_name); 669 return False; 670 } 671 672 if (!string_to_sid(&sid, response.data.domain_info.sid)) { 673 d_printf("Could not convert %s to sid\n", response.data.domain_info.sid); 674 return False; 675 } 676 677 mem_ctx = talloc_new(NULL); 678 if (mem_ctx == NULL) { 679 d_printf("talloc_new failed\n"); 680 return False; 681 } 682 683 num_rids = 0; 684 rids = NULL; 685 p = arg; 686 687 while (next_token(&p, ridstr, " ,\n", sizeof(ridstr))) { 688 uint32 rid = strtoul(ridstr, NULL, 10); 689 ADD_TO_ARRAY(mem_ctx, uint32, rid, &rids, &num_rids); 690 } 691 692 if (rids == NULL) { 693 TALLOC_FREE(mem_ctx); 694 return False; 695 } 696 697 if (!winbind_lookup_rids(mem_ctx, &sid, num_rids, rids, 698 &domain_name, &names, &types)) { 699 d_printf("winbind_lookup_rids failed\n"); 700 TALLOC_FREE(mem_ctx); 701 return False; 702 } 703 704 d_printf("Domain: %s\n", domain_name); 705 706 for (i=0; i<num_rids; i++) { 707 d_printf("%8d: %s (%s)\n", rids[i], names[i], 708 sid_type_lookup(types[i])); 709 } 710 711 TALLOC_FREE(mem_ctx); 712 return True; 713} 714 715/* Convert string to sid */ 716 717static BOOL wbinfo_lookupname(char *name) 718{ 719 struct winbindd_request request; 720 struct winbindd_response response; 721 722 /* Send off request */ 723 724 ZERO_STRUCT(request); 725 ZERO_STRUCT(response); 726 727 parse_wbinfo_domain_user(name, request.data.name.dom_name, 728 request.data.name.name); 729 730 if (winbindd_request_response(WINBINDD_LOOKUPNAME, &request, &response) != 731 NSS_STATUS_SUCCESS) 732 return False; 733 734 /* Display response */ 735 736 d_printf("%s %s (%d)\n", response.data.sid.sid, sid_type_lookup(response.data.sid.type), response.data.sid.type); 737 738 return True; 739} 740 741/* Authenticate a user with a plaintext password */ 742 743static BOOL wbinfo_auth_krb5(char *username, const char *cctype, uint32 flags) 744{ 745 struct winbindd_request request; 746 struct winbindd_response response; 747 NSS_STATUS result; 748 char *p; 749 750 /* Send off request */ 751 752 ZERO_STRUCT(request); 753 ZERO_STRUCT(response); 754 755 p = strchr(username, '%'); 756 757 if (p) { 758 *p = 0; 759 fstrcpy(request.data.auth.user, username); 760 fstrcpy(request.data.auth.pass, p + 1); 761 *p = '%'; 762 } else 763 fstrcpy(request.data.auth.user, username); 764 765 request.flags = flags; 766 767 fstrcpy(request.data.auth.krb5_cc_type, cctype); 768 769 request.data.auth.uid = geteuid(); 770 771 result = winbindd_request_response(WINBINDD_PAM_AUTH, &request, &response); 772 773 /* Display response */ 774 775 d_printf("plaintext kerberos password authentication for [%s] %s (requesting cctype: %s)\n", 776 username, (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed", cctype); 777 778 if (response.data.auth.nt_status) 779 d_fprintf(stderr, "error code was %s (0x%x)\nerror messsage was: %s\n", 780 response.data.auth.nt_status_string, 781 response.data.auth.nt_status, 782 response.data.auth.error_string); 783 784 if (result == NSS_STATUS_SUCCESS) { 785 786 if (request.flags & WBFLAG_PAM_INFO3_TEXT) { 787 if (response.data.auth.info3.user_flgs & LOGON_CACHED_ACCOUNT) { 788 d_printf("user_flgs: LOGON_CACHED_ACCOUNT\n"); 789 } 790 } 791 792 if (response.data.auth.krb5ccname[0] != '\0') { 793 d_printf("credentials were put in: %s\n", response.data.auth.krb5ccname); 794 } else { 795 d_printf("no credentials cached\n"); 796 } 797 } 798 799 return result == NSS_STATUS_SUCCESS; 800} 801 802/* Authenticate a user with a plaintext password */ 803 804static BOOL wbinfo_auth(char *username) 805{ 806 struct winbindd_request request; 807 struct winbindd_response response; 808 NSS_STATUS result; 809 char *p; 810 811 /* Send off request */ 812 813 ZERO_STRUCT(request); 814 ZERO_STRUCT(response); 815 816 p = strchr(username, '%'); 817 818 if (p) { 819 *p = 0; 820 fstrcpy(request.data.auth.user, username); 821 fstrcpy(request.data.auth.pass, p + 1); 822 *p = '%'; 823 } else 824 fstrcpy(request.data.auth.user, username); 825 826 result = winbindd_request_response(WINBINDD_PAM_AUTH, &request, &response); 827 828 /* Display response */ 829 830 d_printf("plaintext password authentication %s\n", 831 (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed"); 832 833 if (response.data.auth.nt_status) 834 d_fprintf(stderr, "error code was %s (0x%x)\nerror messsage was: %s\n", 835 response.data.auth.nt_status_string, 836 response.data.auth.nt_status, 837 response.data.auth.error_string); 838 839 return result == NSS_STATUS_SUCCESS; 840} 841 842/* Authenticate a user with a challenge/response */ 843 844static BOOL wbinfo_auth_crap(char *username) 845{ 846 struct winbindd_request request; 847 struct winbindd_response response; 848 NSS_STATUS result; 849 fstring name_user; 850 fstring name_domain; 851 fstring pass; 852 char *p; 853 854 /* Send off request */ 855 856 ZERO_STRUCT(request); 857 ZERO_STRUCT(response); 858 859 p = strchr(username, '%'); 860 861 if (p) { 862 *p = 0; 863 fstrcpy(pass, p + 1); 864 } 865 866 parse_wbinfo_domain_user(username, name_domain, name_user); 867 868 request.data.auth_crap.logon_parameters = MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT | MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT; 869 870 fstrcpy(request.data.auth_crap.user, name_user); 871 872 fstrcpy(request.data.auth_crap.domain, 873 name_domain); 874 875 generate_random_buffer(request.data.auth_crap.chal, 8); 876 877 if (lp_client_ntlmv2_auth()) { 878 DATA_BLOB server_chal; 879 DATA_BLOB names_blob; 880 881 DATA_BLOB lm_response; 882 DATA_BLOB nt_response; 883 884 server_chal = data_blob(request.data.auth_crap.chal, 8); 885 886 /* Pretend this is a login to 'us', for blob purposes */ 887 names_blob = NTLMv2_generate_names_blob(global_myname(), lp_workgroup()); 888 889 if (!SMBNTLMv2encrypt(name_user, name_domain, pass, &server_chal, 890 &names_blob, 891 &lm_response, &nt_response, NULL)) { 892 data_blob_free(&names_blob); 893 data_blob_free(&server_chal); 894 return False; 895 } 896 data_blob_free(&names_blob); 897 data_blob_free(&server_chal); 898 899 memcpy(request.data.auth_crap.nt_resp, nt_response.data, 900 MIN(nt_response.length, 901 sizeof(request.data.auth_crap.nt_resp))); 902 request.data.auth_crap.nt_resp_len = nt_response.length; 903 904 memcpy(request.data.auth_crap.lm_resp, lm_response.data, 905 MIN(lm_response.length, 906 sizeof(request.data.auth_crap.lm_resp))); 907 request.data.auth_crap.lm_resp_len = lm_response.length; 908 909 data_blob_free(&nt_response); 910 data_blob_free(&lm_response); 911 912 } else { 913 if (lp_client_lanman_auth() 914 && SMBencrypt(pass, request.data.auth_crap.chal, 915 (uchar *)request.data.auth_crap.lm_resp)) { 916 request.data.auth_crap.lm_resp_len = 24; 917 } else { 918 request.data.auth_crap.lm_resp_len = 0; 919 } 920 SMBNTencrypt(pass, request.data.auth_crap.chal, 921 (uchar *)request.data.auth_crap.nt_resp); 922 923 request.data.auth_crap.nt_resp_len = 24; 924 } 925 926 result = winbindd_request_response(WINBINDD_PAM_AUTH_CRAP, &request, &response); 927 928 /* Display response */ 929 930 d_printf("challenge/response password authentication %s\n", 931 (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed"); 932 933 if (response.data.auth.nt_status) 934 d_fprintf(stderr, "error code was %s (0x%x)\nerror messsage was: %s\n", 935 response.data.auth.nt_status_string, 936 response.data.auth.nt_status, 937 response.data.auth.error_string); 938 939 return result == NSS_STATUS_SUCCESS; 940} 941 942/* Authenticate a user with a plaintext password and set a token */ 943 944static BOOL wbinfo_klog(char *username) 945{ 946 struct winbindd_request request; 947 struct winbindd_response response; 948 NSS_STATUS result; 949 char *p; 950 951 /* Send off request */ 952 953 ZERO_STRUCT(request); 954 ZERO_STRUCT(response); 955 956 p = strchr(username, '%'); 957 958 if (p) { 959 *p = 0; 960 fstrcpy(request.data.auth.user, username); 961 fstrcpy(request.data.auth.pass, p + 1); 962 *p = '%'; 963 } else { 964 fstrcpy(request.data.auth.user, username); 965 fstrcpy(request.data.auth.pass, getpass("Password: ")); 966 } 967 968 request.flags |= WBFLAG_PAM_AFS_TOKEN; 969 970 result = winbindd_request_response(WINBINDD_PAM_AUTH, &request, &response); 971 972 /* Display response */ 973 974 d_printf("plaintext password authentication %s\n", 975 (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed"); 976 977 if (response.data.auth.nt_status) 978 d_fprintf(stderr, "error code was %s (0x%x)\nerror messsage was: %s\n", 979 response.data.auth.nt_status_string, 980 response.data.auth.nt_status, 981 response.data.auth.error_string); 982 983 if (result != NSS_STATUS_SUCCESS) 984 return False; 985 986 if (response.extra_data.data == NULL) { 987 d_fprintf(stderr, "Did not get token data\n"); 988 return False; 989 } 990 991 if (!afs_settoken_str((char *)response.extra_data.data)) { 992 d_fprintf(stderr, "Could not set token\n"); 993 return False; 994 } 995 996 d_printf("Successfully created AFS token\n"); 997 return True; 998} 999 1000/* Print domain users */ 1001 1002static BOOL print_domain_users(const char *domain) 1003{ 1004 struct winbindd_request request; 1005 struct winbindd_response response; 1006 const char *extra_data; 1007 fstring name; 1008 1009 /* Send request to winbind daemon */ 1010 1011 ZERO_STRUCT(request); 1012 ZERO_STRUCT(response); 1013 1014 if (domain) { 1015 /* '.' is the special sign for our own domain */ 1016 if ( strequal(domain, ".") ) 1017 fstrcpy( request.domain_name, get_winbind_domain() ); 1018 else 1019 fstrcpy( request.domain_name, domain ); 1020 } 1021 1022 if (winbindd_request_response(WINBINDD_LIST_USERS, &request, &response) != 1023 NSS_STATUS_SUCCESS) 1024 return False; 1025 1026 /* Look through extra data */ 1027 1028 if (!response.extra_data.data) 1029 return False; 1030 1031 extra_data = (const char *)response.extra_data.data; 1032 1033 while(next_token(&extra_data, name, ",", sizeof(fstring))) 1034 d_printf("%s\n", name); 1035 1036 SAFE_FREE(response.extra_data.data); 1037 1038 return True; 1039} 1040 1041/* Print domain groups */ 1042 1043static BOOL print_domain_groups(const char *domain) 1044{ 1045 struct winbindd_request request; 1046 struct winbindd_response response; 1047 const char *extra_data; 1048 fstring name; 1049 1050 ZERO_STRUCT(request); 1051 ZERO_STRUCT(response); 1052 1053 if (domain) { 1054 if ( strequal(domain, ".") ) 1055 fstrcpy( request.domain_name, get_winbind_domain() ); 1056 else 1057 fstrcpy( request.domain_name, domain ); 1058 } 1059 1060 if (winbindd_request_response(WINBINDD_LIST_GROUPS, &request, &response) != 1061 NSS_STATUS_SUCCESS) 1062 return False; 1063 1064 /* Look through extra data */ 1065 1066 if (!response.extra_data.data) 1067 return False; 1068 1069 extra_data = (const char *)response.extra_data.data; 1070 1071 while(next_token(&extra_data, name, ",", sizeof(fstring))) 1072 d_printf("%s\n", name); 1073 1074 SAFE_FREE(response.extra_data.data); 1075 1076 return True; 1077} 1078 1079/* Set the authorised user for winbindd access in secrets.tdb */ 1080 1081static BOOL wbinfo_set_auth_user(char *username) 1082{ 1083 const char *password; 1084 char *p; 1085 fstring user, domain; 1086 1087 /* Separate into user and password */ 1088 1089 parse_wbinfo_domain_user(username, domain, user); 1090 1091 p = strchr(user, '%'); 1092 1093 if (p != NULL) { 1094 *p = 0; 1095 password = p+1; 1096 } else { 1097 char *thepass = getpass("Password: "); 1098 if (thepass) { 1099 password = thepass; 1100 } else 1101 password = ""; 1102 } 1103 1104 /* Store or remove DOMAIN\username%password in secrets.tdb */ 1105 1106 secrets_init(); 1107 1108 if (user[0]) { 1109 1110 if (!secrets_store(SECRETS_AUTH_USER, user, 1111 strlen(user) + 1)) { 1112 d_fprintf(stderr, "error storing username\n"); 1113 return False; 1114 } 1115 1116 /* We always have a domain name added by the 1117 parse_wbinfo_domain_user() function. */ 1118 1119 if (!secrets_store(SECRETS_AUTH_DOMAIN, domain, 1120 strlen(domain) + 1)) { 1121 d_fprintf(stderr, "error storing domain name\n"); 1122 return False; 1123 } 1124 1125 } else { 1126 secrets_delete(SECRETS_AUTH_USER); 1127 secrets_delete(SECRETS_AUTH_DOMAIN); 1128 } 1129 1130 if (password[0]) { 1131 1132 if (!secrets_store(SECRETS_AUTH_PASSWORD, password, 1133 strlen(password) + 1)) { 1134 d_fprintf(stderr, "error storing password\n"); 1135 return False; 1136 } 1137 1138 } else 1139 secrets_delete(SECRETS_AUTH_PASSWORD); 1140 1141 return True; 1142} 1143 1144static void wbinfo_get_auth_user(void) 1145{ 1146 char *user, *domain, *password; 1147 1148 /* Lift data from secrets file */ 1149 1150 secrets_fetch_ipc_userpass(&user, &domain, &password); 1151 1152 if ((!user || !*user) && (!domain || !*domain ) && (!password || !*password)){ 1153 1154 SAFE_FREE(user); 1155 SAFE_FREE(domain); 1156 SAFE_FREE(password); 1157 d_printf("No authorised user configured\n"); 1158 return; 1159 } 1160 1161 /* Pretty print authorised user info */ 1162 1163 d_printf("%s%s%s%s%s\n", domain ? domain : "", domain ? lp_winbind_separator(): "", 1164 user, password ? "%" : "", password ? password : ""); 1165 1166 SAFE_FREE(user); 1167 SAFE_FREE(domain); 1168 SAFE_FREE(password); 1169} 1170 1171static BOOL wbinfo_ping(void) 1172{ 1173 NSS_STATUS result; 1174 1175 result = winbindd_request_response(WINBINDD_PING, NULL, NULL); 1176 1177 /* Display response */ 1178 1179 d_printf("Ping to winbindd %s on fd %d\n", 1180 (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed", winbindd_fd); 1181 1182 return result == NSS_STATUS_SUCCESS; 1183} 1184 1185/* Main program */ 1186 1187enum { 1188 OPT_SET_AUTH_USER = 1000, 1189 OPT_GET_AUTH_USER, 1190 OPT_DOMAIN_NAME, 1191 OPT_SEQUENCE, 1192 OPT_GETDCNAME, 1193 OPT_USERDOMGROUPS, 1194 OPT_USERSIDS, 1195 OPT_ALLOCATE_UID, 1196 OPT_ALLOCATE_GID, 1197 OPT_SEPARATOR, 1198 OPT_LIST_ALL_DOMAINS, 1199 OPT_LIST_OWN_DOMAIN, 1200 OPT_GROUP_INFO, 1201}; 1202 1203int main(int argc, char **argv, char **envp) 1204{ 1205 int opt; 1206 1207 poptContext pc; 1208 static char *string_arg; 1209 static char *opt_domain_name; 1210 static int int_arg; 1211 int result = 1; 1212 1213 struct poptOption long_options[] = { 1214 POPT_AUTOHELP 1215 1216 /* longName, shortName, argInfo, argPtr, value, descrip, 1217 argDesc */ 1218 1219 { "domain-users", 'u', POPT_ARG_NONE, 0, 'u', "Lists all domain users", "domain"}, 1220 { "domain-groups", 'g', POPT_ARG_NONE, 0, 'g', "Lists all domain groups", "domain" }, 1221 { "WINS-by-name", 'N', POPT_ARG_STRING, &string_arg, 'N', "Converts NetBIOS name to IP", "NETBIOS-NAME" }, 1222 { "WINS-by-ip", 'I', POPT_ARG_STRING, &string_arg, 'I', "Converts IP address to NetBIOS name", "IP" }, 1223 { "name-to-sid", 'n', POPT_ARG_STRING, &string_arg, 'n', "Converts name to sid", "NAME" }, 1224 { "sid-to-name", 's', POPT_ARG_STRING, &string_arg, 's', "Converts sid to name", "SID" }, 1225 { "lookup-rids", 'R', POPT_ARG_STRING, &string_arg, 'R', "Converts RIDs to names", "RIDs" }, 1226 { "uid-to-sid", 'U', POPT_ARG_INT, &int_arg, 'U', "Converts uid to sid" , "UID" }, 1227 { "gid-to-sid", 'G', POPT_ARG_INT, &int_arg, 'G', "Converts gid to sid", "GID" }, 1228 { "sid-to-uid", 'S', POPT_ARG_STRING, &string_arg, 'S', "Converts sid to uid", "SID" }, 1229 { "sid-to-gid", 'Y', POPT_ARG_STRING, &string_arg, 'Y', "Converts sid to gid", "SID" }, 1230 { "allocate-uid", 0, POPT_ARG_NONE, 0, OPT_ALLOCATE_UID, 1231 "Get a new UID out of idmap" }, 1232 { "allocate-gid", 0, POPT_ARG_NONE, 0, OPT_ALLOCATE_GID, 1233 "Get a new GID out of idmap" }, 1234 { "check-secret", 't', POPT_ARG_NONE, 0, 't', "Check shared secret" }, 1235 { "trusted-domains", 'm', POPT_ARG_NONE, 0, 'm', "List trusted domains" }, 1236 { "all-domains", 0, POPT_ARG_NONE, 0, OPT_LIST_ALL_DOMAINS, "List all domains (trusted and own domain)" }, 1237 { "own-domain", 0, POPT_ARG_NONE, 0, OPT_LIST_OWN_DOMAIN, "List own domain" }, 1238 { "sequence", 0, POPT_ARG_NONE, 0, OPT_SEQUENCE, "Show sequence numbers of all domains" }, 1239 { "domain-info", 'D', POPT_ARG_STRING, &string_arg, 'D', "Show most of the info we have about the domain" }, 1240 { "user-info", 'i', POPT_ARG_STRING, &string_arg, 'i', "Get user info", "USER" }, 1241 { "group-info", 0, POPT_ARG_STRING, &string_arg, OPT_GROUP_INFO, "Get group info", "GROUP" }, 1242 { "user-groups", 'r', POPT_ARG_STRING, &string_arg, 'r', "Get user groups", "USER" }, 1243 { "user-domgroups", 0, POPT_ARG_STRING, &string_arg, 1244 OPT_USERDOMGROUPS, "Get user domain groups", "SID" }, 1245 { "user-sids", 0, POPT_ARG_STRING, &string_arg, OPT_USERSIDS, "Get user group sids for user SID", "SID" }, 1246 { "authenticate", 'a', POPT_ARG_STRING, &string_arg, 'a', "authenticate user", "user%password" }, 1247 { "set-auth-user", 0, POPT_ARG_STRING, &string_arg, OPT_SET_AUTH_USER, "Store user and password used by winbindd (root only)", "user%password" }, 1248 { "getdcname", 0, POPT_ARG_STRING, &string_arg, OPT_GETDCNAME, 1249 "Get a DC name for a foreign domain", "domainname" }, 1250 { "get-auth-user", 0, POPT_ARG_NONE, NULL, OPT_GET_AUTH_USER, "Retrieve user and password used by winbindd (root only)", NULL }, 1251 { "ping", 'p', POPT_ARG_NONE, 0, 'p', "Ping winbindd to see if it is alive" }, 1252 { "domain", 0, POPT_ARG_STRING, &opt_domain_name, OPT_DOMAIN_NAME, "Define to the domain to restrict operation", "domain" }, 1253#ifdef WITH_FAKE_KASERVER 1254 { "klog", 'k', POPT_ARG_STRING, &string_arg, 'k', "set an AFS token from winbind", "user%password" }, 1255#endif 1256#ifdef HAVE_KRB5 1257 { "krb5auth", 'K', POPT_ARG_STRING, &string_arg, 'K', "authenticate user using Kerberos", "user%password" }, 1258 /* destroys wbinfo --help output */ 1259 /* "user%password,DOM\\user%password,user@EXAMPLE.COM,EXAMPLE.COM\\user%password" }, */ 1260#endif 1261 { "separator", 0, POPT_ARG_NONE, 0, OPT_SEPARATOR, "Get the active winbind separator", NULL }, 1262 POPT_COMMON_VERSION 1263 POPT_TABLEEND 1264 }; 1265 1266 /* Samba client initialisation */ 1267 load_case_tables(); 1268 1269 if (!lp_load(dyn_CONFIGFILE, True, False, False, True)) { 1270 d_fprintf(stderr, "wbinfo: error opening config file %s. Error was %s\n", 1271 dyn_CONFIGFILE, strerror(errno)); 1272 exit(1); 1273 } 1274 1275 if (!init_names()) 1276 return 1; 1277 1278 load_interfaces(); 1279 1280 /* Parse options */ 1281 1282 pc = poptGetContext("wbinfo", argc, (const char **)argv, long_options, 0); 1283 1284 /* Parse command line options */ 1285 1286 if (argc == 1) { 1287 poptPrintHelp(pc, stderr, 0); 1288 return 1; 1289 } 1290 1291 while((opt = poptGetNextOpt(pc)) != -1) { 1292 /* get the generic configuration parameters like --domain */ 1293 } 1294 1295 poptFreeContext(pc); 1296 1297 pc = poptGetContext(NULL, argc, (const char **)argv, long_options, 1298 POPT_CONTEXT_KEEP_FIRST); 1299 1300 while((opt = poptGetNextOpt(pc)) != -1) { 1301 switch (opt) { 1302 case 'u': 1303 if (!print_domain_users(opt_domain_name)) { 1304 d_fprintf(stderr, "Error looking up domain users\n"); 1305 goto done; 1306 } 1307 break; 1308 case 'g': 1309 if (!print_domain_groups(opt_domain_name)) { 1310 d_fprintf(stderr, "Error looking up domain groups\n"); 1311 goto done; 1312 } 1313 break; 1314 case 's': 1315 if (!wbinfo_lookupsid(string_arg)) { 1316 d_fprintf(stderr, "Could not lookup sid %s\n", string_arg); 1317 goto done; 1318 } 1319 break; 1320 case 'R': 1321 if (!wbinfo_lookuprids(opt_domain_name, string_arg)) { 1322 d_fprintf(stderr, "Could not lookup RIDs %s\n", string_arg); 1323 goto done; 1324 } 1325 break; 1326 case 'n': 1327 if (!wbinfo_lookupname(string_arg)) { 1328 d_fprintf(stderr, "Could not lookup name %s\n", string_arg); 1329 goto done; 1330 } 1331 break; 1332 case 'N': 1333 if (!wbinfo_wins_byname(string_arg)) { 1334 d_fprintf(stderr, "Could not lookup WINS by name %s\n", string_arg); 1335 goto done; 1336 } 1337 break; 1338 case 'I': 1339 if (!wbinfo_wins_byip(string_arg)) { 1340 d_fprintf(stderr, "Could not lookup WINS by IP %s\n", string_arg); 1341 goto done; 1342 } 1343 break; 1344 case 'U': 1345 if (!wbinfo_uid_to_sid(int_arg)) { 1346 d_fprintf(stderr, "Could not convert uid %d to sid\n", int_arg); 1347 goto done; 1348 } 1349 break; 1350 case 'G': 1351 if (!wbinfo_gid_to_sid(int_arg)) { 1352 d_fprintf(stderr, "Could not convert gid %d to sid\n", 1353 int_arg); 1354 goto done; 1355 } 1356 break; 1357 case 'S': 1358 if (!wbinfo_sid_to_uid(string_arg)) { 1359 d_fprintf(stderr, "Could not convert sid %s to uid\n", 1360 string_arg); 1361 goto done; 1362 } 1363 break; 1364 case 'Y': 1365 if (!wbinfo_sid_to_gid(string_arg)) { 1366 d_fprintf(stderr, "Could not convert sid %s to gid\n", 1367 string_arg); 1368 goto done; 1369 } 1370 break; 1371 case OPT_ALLOCATE_UID: 1372 if (!wbinfo_allocate_uid()) { 1373 d_fprintf(stderr, "Could not allocate a uid\n"); 1374 goto done; 1375 } 1376 break; 1377 case OPT_ALLOCATE_GID: 1378 if (!wbinfo_allocate_gid()) { 1379 d_fprintf(stderr, "Could not allocate a gid\n"); 1380 goto done; 1381 } 1382 break; 1383 case 't': 1384 if (!wbinfo_check_secret()) { 1385 d_fprintf(stderr, "Could not check secret\n"); 1386 goto done; 1387 } 1388 break; 1389 case 'm': 1390 if (!wbinfo_list_domains(False)) { 1391 d_fprintf(stderr, "Could not list trusted domains\n"); 1392 goto done; 1393 } 1394 break; 1395 case OPT_SEQUENCE: 1396 if (!wbinfo_show_sequence(opt_domain_name)) { 1397 d_fprintf(stderr, "Could not show sequence numbers\n"); 1398 goto done; 1399 } 1400 break; 1401 case 'D': 1402 if (!wbinfo_domain_info(string_arg)) { 1403 d_fprintf(stderr, "Could not get domain info\n"); 1404 goto done; 1405 } 1406 break; 1407 case 'i': 1408 if (!wbinfo_get_userinfo(string_arg)) { 1409 d_fprintf(stderr, "Could not get info for user %s\n", 1410 string_arg); 1411 goto done; 1412 } 1413 break; 1414 case OPT_GROUP_INFO: 1415 if ( !wbinfo_get_groupinfo(string_arg)) { 1416 d_fprintf(stderr, "Could not get info for " 1417 "group %s\n", string_arg); 1418 goto done; 1419 } 1420 break; 1421 case 'r': 1422 if (!wbinfo_get_usergroups(string_arg)) { 1423 d_fprintf(stderr, "Could not get groups for user %s\n", 1424 string_arg); 1425 goto done; 1426 } 1427 break; 1428 case OPT_USERSIDS: 1429 if (!wbinfo_get_usersids(string_arg)) { 1430 d_fprintf(stderr, "Could not get group SIDs for user SID %s\n", 1431 string_arg); 1432 goto done; 1433 } 1434 break; 1435 case OPT_USERDOMGROUPS: 1436 if (!wbinfo_get_userdomgroups(string_arg)) { 1437 d_fprintf(stderr, "Could not get user's domain groups " 1438 "for user SID %s\n", string_arg); 1439 goto done; 1440 } 1441 break; 1442 case 'a': { 1443 BOOL got_error = False; 1444 1445 if (!wbinfo_auth(string_arg)) { 1446 d_fprintf(stderr, "Could not authenticate user %s with " 1447 "plaintext password\n", string_arg); 1448 got_error = True; 1449 } 1450 1451 if (!wbinfo_auth_crap(string_arg)) { 1452 d_fprintf(stderr, "Could not authenticate user %s with " 1453 "challenge/response\n", string_arg); 1454 got_error = True; 1455 } 1456 1457 if (got_error) 1458 goto done; 1459 break; 1460 } 1461 case 'K': { 1462 BOOL got_error = False; 1463 uint32 flags = WBFLAG_PAM_KRB5 | 1464 WBFLAG_PAM_CACHED_LOGIN | 1465 WBFLAG_PAM_FALLBACK_AFTER_KRB5 | 1466 WBFLAG_PAM_INFO3_TEXT; 1467 fstring tok; 1468 int i; 1469 const char *arg[] = { NULL, NULL }; 1470 const char *cctypes[] = { "FILE", 1471 "KCM", 1472 "KCM:0", 1473 "Garbage", 1474 NULL, 1475 "0"}; 1476 1477 arg[0] = string_arg; 1478 1479 while (next_token(arg, tok, LIST_SEP, sizeof(tok))) { 1480 1481 for (i=0; i < ARRAY_SIZE(cctypes); i++) { 1482 if (!wbinfo_auth_krb5(tok, cctypes[i], flags)) { 1483 d_fprintf(stderr, "Could not authenticate user [%s] with " 1484 "Kerberos (ccache: %s)\n", tok, cctypes[i]); 1485 got_error = True; 1486 } 1487 } 1488 } 1489 1490 if (got_error) 1491 goto done; 1492 1493 break; 1494 } 1495 case 'k': 1496 if (!wbinfo_klog(string_arg)) { 1497 d_fprintf(stderr, "Could not klog user\n"); 1498 goto done; 1499 } 1500 break; 1501 case 'p': 1502 if (!wbinfo_ping()) { 1503 d_fprintf(stderr, "could not ping winbindd!\n"); 1504 goto done; 1505 } 1506 break; 1507 case OPT_SET_AUTH_USER: 1508 if (!wbinfo_set_auth_user(string_arg)) { 1509 goto done; 1510 } 1511 break; 1512 case OPT_GET_AUTH_USER: 1513 wbinfo_get_auth_user(); 1514 break; 1515 case OPT_GETDCNAME: 1516 if (!wbinfo_getdcname(string_arg)) { 1517 goto done; 1518 } 1519 break; 1520 case OPT_SEPARATOR: { 1521 const char sep = winbind_separator_int(True); 1522 if ( !sep ) { 1523 goto done; 1524 } 1525 d_printf("%c\n", sep); 1526 break; 1527 } 1528 case OPT_LIST_ALL_DOMAINS: 1529 if (!wbinfo_list_domains(True)) { 1530 goto done; 1531 } 1532 break; 1533 case OPT_LIST_OWN_DOMAIN: 1534 if (!wbinfo_list_own_domain()) { 1535 goto done; 1536 } 1537 break; 1538 /* generic configuration options */ 1539 case OPT_DOMAIN_NAME: 1540 break; 1541 default: 1542 d_fprintf(stderr, "Invalid option\n"); 1543 poptPrintHelp(pc, stderr, 0); 1544 goto done; 1545 } 1546 } 1547 1548 result = 0; 1549 1550 /* Exit code */ 1551 1552 done: 1553 poptFreeContext(pc); 1554 return result; 1555} 1556