Rework Samba3 to use new libcli/auth code (partial)
[kai/samba.git] / nsswitch / wbinfo.c
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 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 #include "winbind_client.h"
25 #include "libwbclient/wbclient.h"
26 #include "../libcli/auth/libcli_auth.h"
27
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_WINBIND
30
31 static struct wbcInterfaceDetails *init_interface_details(void)
32 {
33         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
34         static struct wbcInterfaceDetails *details;
35
36         if (details) {
37                 return details;
38         }
39
40         wbc_status = wbcInterfaceDetails(&details);
41         if (!WBC_ERROR_IS_OK(wbc_status)) {
42                 d_fprintf(stderr, "could not obtain winbind interface details!\n");
43         }
44
45         return details;
46 }
47
48 static char winbind_separator_int(bool strict)
49 {
50         struct wbcInterfaceDetails *details;
51         static bool got_sep;
52         static char sep;
53
54         if (got_sep)
55                 return sep;
56
57         details = init_interface_details();
58
59         if (!details) {
60                 d_fprintf(stderr, "could not obtain winbind separator!\n");
61                 if (strict) {
62                         return 0;
63                 }
64                 /* HACK: (this module should not call lp_ funtions) */
65                 return *lp_winbind_separator();
66         }
67
68         sep = details->winbind_separator;
69         got_sep = true;
70
71         if (!sep) {
72                 d_fprintf(stderr, "winbind separator was NULL!\n");
73                 if (strict) {
74                         return 0;
75                 }
76                 /* HACK: (this module should not call lp_ funtions) */
77                 sep = *lp_winbind_separator();
78         }
79
80         return sep;
81 }
82
83 static char winbind_separator(void)
84 {
85         return winbind_separator_int(false);
86 }
87
88 static const char *get_winbind_domain(void)
89 {
90         static struct wbcInterfaceDetails *details;
91
92         details = init_interface_details();
93
94         if (!details) {
95                 d_fprintf(stderr, "could not obtain winbind domain name!\n");
96
97                 /* HACK: (this module should not call lp_ functions) */
98                 return lp_workgroup();
99         }
100
101         return details->netbios_domain;
102 }
103
104 /* Copy of parse_domain_user from winbindd_util.c.  Parse a string of the
105    form DOMAIN/user into a domain and a user */
106
107 static bool parse_wbinfo_domain_user(const char *domuser, fstring domain,
108                                      fstring user)
109 {
110
111         char *p = strchr(domuser,winbind_separator());
112
113         if (!p) {
114                 /* Maybe it was a UPN? */
115                 if ((p = strchr(domuser, '@')) != NULL) {
116                         fstrcpy(domain, "");
117                         fstrcpy(user, domuser);
118                         return true;
119                 }
120
121                 fstrcpy(user, domuser);
122                 fstrcpy(domain, get_winbind_domain());
123                 return true;
124         }
125
126         fstrcpy(user, p+1);
127         fstrcpy(domain, domuser);
128         domain[PTR_DIFF(p, domuser)] = 0;
129         strupper_m(domain);
130
131         return true;
132 }
133
134 /* Parse string of "uid,sid" or "gid,sid" into separate int and string values.
135  * Return true if input was valid, false otherwise. */
136 static bool parse_mapping_arg(char *arg, int *id, char **sid)
137 {
138         char *tmp, *endptr;
139
140         if (!arg || !*arg)
141                 return false;
142
143         tmp = strtok(arg, ",");
144         *sid = strtok(NULL, ",");
145
146         if (!tmp || !*tmp || !*sid || !**sid)
147                 return false;
148
149         /* Because atoi() can return 0 on invalid input, which would be a valid
150          * UID/GID we must use strtoul() and do error checking */
151         *id = strtoul(tmp, &endptr, 10);
152
153         if (endptr[0] != '\0')
154                 return false;
155
156         return true;
157 }
158
159 /* pull pwent info for a given user */
160
161 static bool wbinfo_get_userinfo(char *user)
162 {
163         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
164         struct passwd *pwd = NULL;
165
166         wbc_status = wbcGetpwnam(user, &pwd);
167         if (!WBC_ERROR_IS_OK(wbc_status)) {
168                 return false;
169         }
170
171         d_printf("%s:%s:%d:%d:%s:%s:%s\n",
172                  pwd->pw_name,
173                  pwd->pw_passwd,
174                  pwd->pw_uid,
175                  pwd->pw_gid,
176                  pwd->pw_gecos,
177                  pwd->pw_dir,
178                  pwd->pw_shell);
179
180         return true;
181 }
182
183 /* pull pwent info for a given uid */
184 static bool wbinfo_get_uidinfo(int uid)
185 {
186         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
187         struct passwd *pwd = NULL;
188
189         wbc_status = wbcGetpwuid(uid, &pwd);
190         if (!WBC_ERROR_IS_OK(wbc_status)) {
191                 return false;
192         }
193
194         d_printf("%s:%s:%d:%d:%s:%s:%s\n",
195                  pwd->pw_name,
196                  pwd->pw_passwd,
197                  pwd->pw_uid,
198                  pwd->pw_gid,
199                  pwd->pw_gecos,
200                  pwd->pw_dir,
201                  pwd->pw_shell);
202
203         return true;
204 }
205
206 static bool wbinfo_get_user_sidinfo(const char *sid_str)
207 {
208         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
209         struct passwd *pwd = NULL;
210         struct wbcDomainSid sid;
211
212         wbc_status = wbcStringToSid(sid_str, &sid);
213         wbc_status = wbcGetpwsid(&sid, &pwd);
214         if (!WBC_ERROR_IS_OK(wbc_status)) {
215                 return false;
216         }
217
218         d_printf("%s:%s:%d:%d:%s:%s:%s\n",
219                  pwd->pw_name,
220                  pwd->pw_passwd,
221                  pwd->pw_uid,
222                  pwd->pw_gid,
223                  pwd->pw_gecos,
224                  pwd->pw_dir,
225                  pwd->pw_shell);
226
227         return true;
228 }
229
230
231 /* pull grent for a given group */
232 static bool wbinfo_get_groupinfo(const char *group)
233 {
234         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
235         struct group *grp;
236
237         wbc_status = wbcGetgrnam(group, &grp);
238         if (!WBC_ERROR_IS_OK(wbc_status)) {
239                 return false;
240         }
241
242         d_printf("%s:%s:%d\n",
243                  grp->gr_name,
244                  grp->gr_passwd,
245                  grp->gr_gid);
246
247         wbcFreeMemory(grp);
248
249         return true;
250 }
251
252 /* pull grent for a given gid */
253 static bool wbinfo_get_gidinfo(int gid)
254 {
255         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
256         struct group *grp;
257
258         wbc_status = wbcGetgrgid(gid, &grp);
259         if (!WBC_ERROR_IS_OK(wbc_status)) {
260                 return false;
261         }
262
263         d_printf("%s:%s:%d\n",
264                  grp->gr_name,
265                  grp->gr_passwd,
266                  grp->gr_gid);
267
268         wbcFreeMemory(grp);
269
270         return true;
271 }
272
273 /* List groups a user is a member of */
274
275 static bool wbinfo_get_usergroups(const char *user)
276 {
277         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
278         uint32_t num_groups;
279         uint32_t i;
280         gid_t *groups = NULL;
281
282         /* Send request */
283
284         wbc_status = wbcGetGroups(user, &num_groups, &groups);
285         if (!WBC_ERROR_IS_OK(wbc_status)) {
286                 return false;
287         }
288
289         for (i = 0; i < num_groups; i++) {
290                 d_printf("%d\n", (int)groups[i]);
291         }
292
293         wbcFreeMemory(groups);
294
295         return true;
296 }
297
298
299 /* List group SIDs a user SID is a member of */
300 static bool wbinfo_get_usersids(const char *user_sid_str)
301 {
302         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
303         uint32_t num_sids;
304         uint32_t i;
305         struct wbcDomainSid user_sid, *sids = NULL;
306
307         /* Send request */
308
309         wbc_status = wbcStringToSid(user_sid_str, &user_sid);
310         if (!WBC_ERROR_IS_OK(wbc_status)) {
311                 return false;
312         }
313
314         wbc_status = wbcLookupUserSids(&user_sid, false, &num_sids, &sids);
315         if (!WBC_ERROR_IS_OK(wbc_status)) {
316                 return false;
317         }
318
319         for (i = 0; i < num_sids; i++) {
320                 char *str = NULL;
321                 wbc_status = wbcSidToString(&sids[i], &str);
322                 if (!WBC_ERROR_IS_OK(wbc_status)) {
323                         wbcFreeMemory(sids);
324                         return false;
325                 }
326                 d_printf("%s\n", str);
327                 wbcFreeMemory(str);
328         }
329
330         wbcFreeMemory(sids);
331
332         return true;
333 }
334
335 static bool wbinfo_get_userdomgroups(const char *user_sid_str)
336 {
337         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
338         uint32_t num_sids;
339         uint32_t i;
340         struct wbcDomainSid user_sid, *sids = NULL;
341
342         /* Send request */
343
344         wbc_status = wbcStringToSid(user_sid_str, &user_sid);
345         if (!WBC_ERROR_IS_OK(wbc_status)) {
346                 return false;
347         }
348
349         wbc_status = wbcLookupUserSids(&user_sid, true, &num_sids, &sids);
350         if (!WBC_ERROR_IS_OK(wbc_status)) {
351                 return false;
352         }
353
354         for (i = 0; i < num_sids; i++) {
355                 char *str = NULL;
356                 wbc_status = wbcSidToString(&sids[i], &str);
357                 if (!WBC_ERROR_IS_OK(wbc_status)) {
358                         wbcFreeMemory(sids);
359                         return false;
360                 }
361                 d_printf("%s\n", str);
362                 wbcFreeMemory(str);
363         }
364
365         wbcFreeMemory(sids);
366
367         return true;
368 }
369
370 static bool wbinfo_get_sidaliases(const char *domain,
371                                   const char *user_sid_str)
372 {
373         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
374         struct wbcDomainInfo *dinfo = NULL;
375         uint32_t i;
376         struct wbcDomainSid user_sid;
377         uint32_t *alias_rids = NULL;
378         uint32_t num_alias_rids;
379         char *domain_sid_str = NULL;
380
381         /* Send request */
382         if ((domain == NULL) || (strequal(domain, ".")) ||
383            (domain[0] == '\0')) {
384                 domain = get_winbind_domain();
385         }
386
387         /* Send request */
388
389         wbc_status = wbcDomainInfo(domain, &dinfo);
390         if (!WBC_ERROR_IS_OK(wbc_status)) {
391                 d_printf("wbcDomainInfo(%s) failed: %s\n", domain,
392                          wbcErrorString(wbc_status));
393                 goto done;
394         }
395         wbc_status = wbcStringToSid(user_sid_str, &user_sid);
396         if (!WBC_ERROR_IS_OK(wbc_status)) {
397                 goto done;
398         }
399
400         wbc_status = wbcGetSidAliases(&dinfo->sid, &user_sid, 1,
401             &alias_rids, &num_alias_rids);
402         if (!WBC_ERROR_IS_OK(wbc_status)) {
403                 goto done;
404         }
405
406         wbc_status = wbcSidToString(&dinfo->sid, &domain_sid_str);
407         if (!WBC_ERROR_IS_OK(wbc_status)) {
408                 goto done;
409         }
410
411         for (i = 0; i < num_alias_rids; i++) {
412                 d_printf("%s-%d\n", domain_sid_str, alias_rids[i]);
413         }
414
415         wbcFreeMemory(alias_rids);
416
417 done:
418         if (domain_sid_str) {
419                 wbcFreeMemory(domain_sid_str);
420         }
421         if (dinfo) {
422                 wbcFreeMemory(dinfo);
423         }
424         return (WBC_ERR_SUCCESS == wbc_status);
425 }
426
427
428 /* Convert NetBIOS name to IP */
429
430 static bool wbinfo_wins_byname(const char *name)
431 {
432         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
433         char *ip = NULL;
434
435         wbc_status = wbcResolveWinsByName(name, &ip);
436         if (!WBC_ERROR_IS_OK(wbc_status)) {
437                 return false;
438         }
439
440         /* Display response */
441
442         d_printf("%s\n", ip);
443
444         wbcFreeMemory(ip);
445
446         return true;
447 }
448
449 /* Convert IP to NetBIOS name */
450
451 static bool wbinfo_wins_byip(const char *ip)
452 {
453         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
454         char *name = NULL;
455
456         wbc_status = wbcResolveWinsByIP(ip, &name);
457         if (!WBC_ERROR_IS_OK(wbc_status)) {
458                 return false;
459         }
460
461         /* Display response */
462
463         d_printf("%s\n", name);
464
465         wbcFreeMemory(name);
466
467         return true;
468 }
469
470 /* List all/trusted domains */
471
472 static bool wbinfo_list_domains(bool list_all_domains, bool verbose)
473 {
474         struct wbcDomainInfo *domain_list = NULL;
475         size_t num_domains;
476         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
477         bool print_all = !list_all_domains && verbose;
478         int i;
479
480         wbc_status = wbcListTrusts(&domain_list, &num_domains);
481         if (!WBC_ERROR_IS_OK(wbc_status)) {
482                 return false;
483         }
484
485         if (print_all) {
486                 d_printf("%-16s%-24s%-12s%-12s%-5s%-5s\n",
487                          "Domain Name", "DNS Domain", "Trust Type",
488                          "Transitive", "In", "Out");
489         }
490
491         for (i=0; i<num_domains; i++) {
492                 if (print_all) {
493                         d_printf("%-16s", domain_list[i].short_name);
494                 } else {
495                         d_printf("%s", domain_list[i].short_name);
496                         d_printf("\n");
497                         continue;
498                 }
499
500                 d_printf("%-24s", domain_list[i].dns_name);
501
502                 switch(domain_list[i].trust_type) {
503                 case WBC_DOMINFO_TRUSTTYPE_NONE:
504                         d_printf("None        ");
505                         break;
506                 case WBC_DOMINFO_TRUSTTYPE_FOREST:
507                         d_printf("Forest      ");
508                         break;
509                 case WBC_DOMINFO_TRUSTTYPE_EXTERNAL:
510                         d_printf("External    ");
511                         break;
512                 case WBC_DOMINFO_TRUSTTYPE_IN_FOREST:
513                         d_printf("In-Forest   ");
514                         break;
515                 }
516
517                 if (domain_list[i].trust_flags & WBC_DOMINFO_TRUST_TRANSITIVE) {
518                         d_printf("Yes         ");
519                 } else {
520                         d_printf("No          ");
521                 }
522
523                 if (domain_list[i].trust_flags & WBC_DOMINFO_TRUST_INCOMING) {
524                         d_printf("Yes  ");
525                 } else {
526                         d_printf("No   ");
527                 }
528
529                 if (domain_list[i].trust_flags & WBC_DOMINFO_TRUST_OUTGOING) {
530                         d_printf("Yes  ");
531                 } else {
532                         d_printf("No   ");
533                 }
534
535                 d_printf("\n");
536         }
537
538         return true;
539 }
540
541 /* List own domain */
542
543 static bool wbinfo_list_own_domain(void)
544 {
545         d_printf("%s\n", get_winbind_domain());
546
547         return true;
548 }
549
550 /* show sequence numbers */
551 static bool wbinfo_show_sequence(const char *domain)
552 {
553         d_printf("This command has been deprecated.  Please use the --online-status option instead.\n");
554         return false;
555 }
556
557 /* show sequence numbers */
558 static bool wbinfo_show_onlinestatus(const char *domain)
559 {
560         struct wbcDomainInfo *domain_list = NULL;
561         size_t num_domains;
562         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
563         int i;
564
565         wbc_status = wbcListTrusts(&domain_list, &num_domains);
566         if (!WBC_ERROR_IS_OK(wbc_status)) {
567                 return false;
568         }
569
570         for (i=0; i<num_domains; i++) {
571                 bool is_offline;
572
573                 if (domain) {
574                         if (!strequal(domain_list[i].short_name, domain)) {
575                                 continue;
576                         }
577                 }
578
579                 is_offline = (domain_list[i].domain_flags & WBC_DOMINFO_DOMAIN_OFFLINE);
580
581                 d_printf("%s : %s\n",
582                          domain_list[i].short_name,
583                          is_offline ? "offline" : "online" );
584         }
585
586         return true;
587 }
588
589
590 /* Show domain info */
591
592 static bool wbinfo_domain_info(const char *domain)
593 {
594         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
595         struct wbcDomainInfo *dinfo = NULL;
596         char *sid_str = NULL;
597
598         if ((domain == NULL) || (strequal(domain, ".")) || (domain[0] == '\0')) {
599                 domain = get_winbind_domain();
600         }
601
602         /* Send request */
603
604         wbc_status = wbcDomainInfo(domain, &dinfo);
605         if (!WBC_ERROR_IS_OK(wbc_status)) {
606                 return false;
607         }
608
609         wbc_status = wbcSidToString(&dinfo->sid, &sid_str);
610         if (!WBC_ERROR_IS_OK(wbc_status)) {
611                 wbcFreeMemory(dinfo);
612                 return false;
613         }
614
615         /* Display response */
616
617         d_printf("Name              : %s\n", dinfo->short_name);
618         d_printf("Alt_Name          : %s\n", dinfo->dns_name);
619
620         d_printf("SID               : %s\n", sid_str);
621
622         d_printf("Active Directory  : %s\n",
623                  (dinfo->domain_flags & WBC_DOMINFO_DOMAIN_AD) ? "Yes" : "No");
624         d_printf("Native            : %s\n",
625                  (dinfo->domain_flags & WBC_DOMINFO_DOMAIN_NATIVE) ? "Yes" : "No");
626
627         d_printf("Primary           : %s\n",
628                  (dinfo->domain_flags & WBC_DOMINFO_DOMAIN_PRIMARY) ? "Yes" : "No");
629
630         wbcFreeMemory(sid_str);
631         wbcFreeMemory(dinfo);
632
633         return true;
634 }
635
636 /* Get a foreign DC's name */
637 static bool wbinfo_getdcname(const char *domain_name)
638 {
639         struct winbindd_request request;
640         struct winbindd_response response;
641
642         ZERO_STRUCT(request);
643         ZERO_STRUCT(response);
644
645         fstrcpy(request.domain_name, domain_name);
646
647         /* Send request */
648
649         if (winbindd_request_response(WINBINDD_GETDCNAME, &request, &response) !=
650             NSS_STATUS_SUCCESS) {
651                 d_fprintf(stderr, "Could not get dc name for %s\n", domain_name);
652                 return false;
653         }
654
655         /* Display response */
656
657         d_printf("%s\n", response.data.dc_name);
658
659         return true;
660 }
661
662 /* Find a DC */
663 static bool wbinfo_dsgetdcname(const char *domain_name, uint32_t flags)
664 {
665         struct winbindd_request request;
666         struct winbindd_response response;
667
668         ZERO_STRUCT(request);
669         ZERO_STRUCT(response);
670
671         fstrcpy(request.data.dsgetdcname.domain_name, domain_name);
672         request.data.dsgetdcname.flags = flags;
673
674         request.flags |= DS_DIRECTORY_SERVICE_REQUIRED;
675
676         /* Send request */
677
678         if (winbindd_request_response(WINBINDD_DSGETDCNAME, &request, &response) !=
679             NSS_STATUS_SUCCESS) {
680                 d_fprintf(stderr, "Could not find dc for %s\n", domain_name);
681                 return false;
682         }
683
684         /* Display response */
685
686         d_printf("%s\n", response.data.dsgetdcname.dc_unc);
687         d_printf("%s\n", response.data.dsgetdcname.dc_address);
688         d_printf("%d\n", response.data.dsgetdcname.dc_address_type);
689         d_printf("%s\n", response.data.dsgetdcname.domain_guid);
690         d_printf("%s\n", response.data.dsgetdcname.domain_name);
691         d_printf("%s\n", response.data.dsgetdcname.forest_name);
692         d_printf("0x%08x\n", response.data.dsgetdcname.dc_flags);
693         d_printf("%s\n", response.data.dsgetdcname.dc_site_name);
694         d_printf("%s\n", response.data.dsgetdcname.client_site_name);
695
696         return true;
697 }
698
699 /* Check trust account password */
700
701 static bool wbinfo_check_secret(void)
702 {
703         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
704         struct wbcAuthErrorInfo *error = NULL;
705
706         wbc_status = wbcCheckTrustCredentials(NULL, &error);
707
708         d_printf("checking the trust secret via RPC calls %s\n",
709                  WBC_ERROR_IS_OK(wbc_status) ? "succeeded" : "failed");
710
711         if (wbc_status == WBC_ERR_AUTH_ERROR) {
712                 d_fprintf(stderr, "error code was %s (0x%x)\n",
713                           error->nt_string, error->nt_status);
714                 wbcFreeMemory(error);
715         }
716         if (!WBC_ERROR_IS_OK(wbc_status)) {
717                 return false;
718         }
719
720         return true;
721 }
722
723 /* Convert uid to sid */
724
725 static bool wbinfo_uid_to_sid(uid_t uid)
726 {
727         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
728         struct wbcDomainSid sid;
729         char *sid_str = NULL;
730
731         /* Send request */
732
733         wbc_status = wbcUidToSid(uid, &sid);
734         if (!WBC_ERROR_IS_OK(wbc_status)) {
735                 return false;
736         }
737
738         wbc_status = wbcSidToString(&sid, &sid_str);
739         if (!WBC_ERROR_IS_OK(wbc_status)) {
740                 return false;
741         }
742
743         /* Display response */
744
745         d_printf("%s\n", sid_str);
746
747         wbcFreeMemory(sid_str);
748
749         return true;
750 }
751
752 /* Convert gid to sid */
753
754 static bool wbinfo_gid_to_sid(gid_t gid)
755 {
756         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
757         struct wbcDomainSid sid;
758         char *sid_str = NULL;
759
760         /* Send request */
761
762         wbc_status = wbcGidToSid(gid, &sid);
763         if (!WBC_ERROR_IS_OK(wbc_status)) {
764                 return false;
765         }
766
767         wbc_status = wbcSidToString(&sid, &sid_str);
768         if (!WBC_ERROR_IS_OK(wbc_status)) {
769                 return false;
770         }
771
772         /* Display response */
773
774         d_printf("%s\n", sid_str);
775
776         wbcFreeMemory(sid_str);
777
778         return true;
779 }
780
781 /* Convert sid to uid */
782
783 static bool wbinfo_sid_to_uid(const char *sid_str)
784 {
785         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
786         struct wbcDomainSid sid;
787         uid_t uid;
788
789         /* Send request */
790
791         wbc_status = wbcStringToSid(sid_str, &sid);
792         if (!WBC_ERROR_IS_OK(wbc_status)) {
793                 return false;
794         }
795
796         wbc_status = wbcSidToUid(&sid, &uid);
797         if (!WBC_ERROR_IS_OK(wbc_status)) {
798                 return false;
799         }
800
801         /* Display response */
802
803         d_printf("%d\n", (int)uid);
804
805         return true;
806 }
807
808 static bool wbinfo_sid_to_gid(const char *sid_str)
809 {
810         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
811         struct wbcDomainSid sid;
812         gid_t gid;
813
814         /* Send request */
815
816         wbc_status = wbcStringToSid(sid_str, &sid);
817         if (!WBC_ERROR_IS_OK(wbc_status)) {
818                 return false;
819         }
820
821         wbc_status = wbcSidToGid(&sid, &gid);
822         if (!WBC_ERROR_IS_OK(wbc_status)) {
823                 return false;
824         }
825
826         /* Display response */
827
828         d_printf("%d\n", (int)gid);
829
830         return true;
831 }
832
833 static bool wbinfo_allocate_uid(void)
834 {
835         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
836         uid_t uid;
837
838         /* Send request */
839
840         wbc_status = wbcAllocateUid(&uid);
841         if (!WBC_ERROR_IS_OK(wbc_status)) {
842                 return false;
843         }
844
845         /* Display response */
846
847         d_printf("New uid: %d\n", uid);
848
849         return true;
850 }
851
852 static bool wbinfo_allocate_gid(void)
853 {
854         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
855         gid_t gid;
856
857         /* Send request */
858
859         wbc_status = wbcAllocateGid(&gid);
860         if (!WBC_ERROR_IS_OK(wbc_status)) {
861                 return false;
862         }
863
864         /* Display response */
865
866         d_printf("New gid: %d\n", gid);
867
868         return true;
869 }
870
871 static bool wbinfo_set_uid_mapping(uid_t uid, const char *sid_str)
872 {
873         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
874         struct wbcDomainSid sid;
875
876         /* Send request */
877
878         wbc_status = wbcStringToSid(sid_str, &sid);
879         if (!WBC_ERROR_IS_OK(wbc_status)) {
880                 return false;
881         }
882
883         wbc_status = wbcSetUidMapping(uid, &sid);
884         if (!WBC_ERROR_IS_OK(wbc_status)) {
885                 return false;
886         }
887
888         /* Display response */
889
890         d_printf("uid %d now mapped to sid %s\n", uid, sid_str);
891
892         return true;
893 }
894
895 static bool wbinfo_set_gid_mapping(gid_t gid, const char *sid_str)
896 {
897         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
898         struct wbcDomainSid sid;
899
900         /* Send request */
901
902         wbc_status = wbcStringToSid(sid_str, &sid);
903         if (!WBC_ERROR_IS_OK(wbc_status)) {
904                 return false;
905         }
906
907         wbc_status = wbcSetGidMapping(gid, &sid);
908         if (!WBC_ERROR_IS_OK(wbc_status)) {
909                 return false;
910         }
911
912         /* Display response */
913
914         d_printf("gid %d now mapped to sid %s\n", gid, sid_str);
915
916         return true;
917 }
918
919 static bool wbinfo_remove_uid_mapping(uid_t uid, const char *sid_str)
920 {
921         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
922         struct wbcDomainSid sid;
923
924         /* Send request */
925
926         wbc_status = wbcStringToSid(sid_str, &sid);
927         if (!WBC_ERROR_IS_OK(wbc_status)) {
928                 return false;
929         }
930
931         wbc_status = wbcRemoveUidMapping(uid, &sid);
932         if (!WBC_ERROR_IS_OK(wbc_status)) {
933                 return false;
934         }
935
936         /* Display response */
937
938         d_printf("Removed uid %d to sid %s mapping\n", uid, sid_str);
939
940         return true;
941 }
942
943 static bool wbinfo_remove_gid_mapping(gid_t gid, const char *sid_str)
944 {
945         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
946         struct wbcDomainSid sid;
947
948         /* Send request */
949
950         wbc_status = wbcStringToSid(sid_str, &sid);
951         if (!WBC_ERROR_IS_OK(wbc_status)) {
952                 return false;
953         }
954
955         wbc_status = wbcRemoveGidMapping(gid, &sid);
956         if (!WBC_ERROR_IS_OK(wbc_status)) {
957                 return false;
958         }
959
960         /* Display response */
961
962         d_printf("Removed gid %d to sid %s mapping\n", gid, sid_str);
963
964         return true;
965 }
966
967 /* Convert sid to string */
968
969 static bool wbinfo_lookupsid(const char *sid_str)
970 {
971         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
972         struct wbcDomainSid sid;
973         char *domain;
974         char *name;
975         enum wbcSidType type;
976
977         /* Send off request */
978
979         wbc_status = wbcStringToSid(sid_str, &sid);
980         if (!WBC_ERROR_IS_OK(wbc_status)) {
981                 return false;
982         }
983
984         wbc_status = wbcLookupSid(&sid, &domain, &name, &type);
985         if (!WBC_ERROR_IS_OK(wbc_status)) {
986                 return false;
987         }
988
989         /* Display response */
990
991         d_printf("%s%c%s %d\n",
992                  domain, winbind_separator(), name, type);
993
994         return true;
995 }
996
997 /* Convert sid to fullname */
998
999 static bool wbinfo_lookupsid_fullname(const char *sid_str)
1000 {
1001         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
1002         struct wbcDomainSid sid;
1003         char *domain;
1004         char *name;
1005         enum wbcSidType type;
1006
1007         /* Send off request */
1008
1009         wbc_status = wbcStringToSid(sid_str, &sid);
1010         if (!WBC_ERROR_IS_OK(wbc_status)) {
1011                 return false;
1012         }
1013
1014         wbc_status = wbcGetDisplayName(&sid, &domain, &name, &type);
1015         if (!WBC_ERROR_IS_OK(wbc_status)) {
1016                 return false;
1017         }
1018
1019         /* Display response */
1020
1021         d_printf("%s%c%s %d\n",
1022                  domain, winbind_separator(), name, type);
1023
1024         return true;
1025 }
1026
1027 /* Lookup a list of RIDs */
1028
1029 static bool wbinfo_lookuprids(const char *domain, const char *arg)
1030 {
1031         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
1032         struct wbcDomainInfo *dinfo = NULL;
1033         char *domain_name = NULL;
1034         const char **names = NULL;
1035         enum wbcSidType *types = NULL;
1036         size_t i;
1037         int num_rids;
1038         uint32 *rids = NULL;
1039         const char *p;
1040         char *ridstr;
1041         TALLOC_CTX *mem_ctx = NULL;
1042         bool ret = false;
1043
1044         if ((domain == NULL) || (strequal(domain, ".")) || (domain[0] == '\0')) {
1045                 domain = get_winbind_domain();
1046         }
1047
1048         /* Send request */
1049
1050         wbc_status = wbcDomainInfo(domain, &dinfo);
1051         if (!WBC_ERROR_IS_OK(wbc_status)) {
1052                 d_printf("wbcDomainInfo(%s) failed: %s\n", domain,
1053                          wbcErrorString(wbc_status));
1054                 goto done;
1055         }
1056
1057         mem_ctx = talloc_new(NULL);
1058         if (mem_ctx == NULL) {
1059                 d_printf("talloc_new failed\n");
1060                 goto done;
1061         }
1062
1063         num_rids = 0;
1064         rids = NULL;
1065         p = arg;
1066
1067         while (next_token_talloc(mem_ctx, &p, &ridstr, " ,\n")) {
1068                 uint32 rid = strtoul(ridstr, NULL, 10);
1069                 ADD_TO_ARRAY(mem_ctx, uint32, rid, &rids, &num_rids);
1070         }
1071
1072         if (rids == NULL) {
1073                 d_printf("no rids\n");
1074                 goto done;
1075         }
1076
1077         wbc_status = wbcLookupRids(&dinfo->sid, num_rids, rids,
1078                                    (const char **)&domain_name, &names, &types);
1079         if (!WBC_ERROR_IS_OK(wbc_status)) {
1080                 d_printf("winbind_lookup_rids failed: %s\n",
1081                          wbcErrorString(wbc_status));
1082                 goto done;
1083         }
1084
1085         d_printf("Domain: %s\n", domain_name);
1086
1087         for (i=0; i<num_rids; i++) {
1088                 d_printf("%8d: %s (%s)\n", rids[i], names[i],
1089                          sid_type_lookup(types[i]));
1090         }
1091
1092         ret = true;
1093 done:
1094         if (dinfo) {
1095                 wbcFreeMemory(dinfo);
1096         }
1097         if (domain_name) {
1098                 wbcFreeMemory(domain_name);
1099         }
1100         if (names) {
1101                 wbcFreeMemory(names);
1102         }
1103         if (types) {
1104                 wbcFreeMemory(types);
1105         }
1106         TALLOC_FREE(mem_ctx);
1107         return ret;
1108 }
1109
1110 /* Convert string to sid */
1111
1112 static bool wbinfo_lookupname(const char *full_name)
1113 {
1114         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
1115         struct wbcDomainSid sid;
1116         char *sid_str;
1117         enum wbcSidType type;
1118         fstring domain_name;
1119         fstring account_name;
1120
1121         /* Send off request */
1122
1123         parse_wbinfo_domain_user(full_name, domain_name,
1124                                  account_name);
1125
1126         wbc_status = wbcLookupName(domain_name, account_name,
1127                                    &sid, &type);
1128         if (!WBC_ERROR_IS_OK(wbc_status)) {
1129                 return false;
1130         }
1131
1132         wbc_status = wbcSidToString(&sid, &sid_str);
1133         if (!WBC_ERROR_IS_OK(wbc_status)) {
1134                 return false;
1135         }
1136
1137         /* Display response */
1138
1139         d_printf("%s %s (%d)\n", sid_str, sid_type_lookup(type), type);
1140
1141         wbcFreeMemory(sid_str);
1142
1143         return true;
1144 }
1145
1146 static char *wbinfo_prompt_pass(const char *prefix,
1147                                 const char *username)
1148 {
1149         char *prompt;
1150         const char *ret = NULL;
1151
1152         prompt = talloc_asprintf(talloc_tos(), "Enter %s's ", username);
1153         if (!prompt) {
1154                 return NULL;
1155         }
1156         if (prefix) {
1157                 prompt = talloc_asprintf_append(prompt, "%s ", prefix);
1158                 if (!prompt) {
1159                         return NULL;
1160                 }
1161         }
1162         prompt = talloc_asprintf_append(prompt, "password: ");
1163         if (!prompt) {
1164                 return NULL;
1165         }
1166
1167         ret = getpass(prompt);
1168         TALLOC_FREE(prompt);
1169
1170         return SMB_STRDUP(ret);
1171 }
1172
1173 /* Authenticate a user with a plaintext password */
1174
1175 static bool wbinfo_auth_krb5(char *username, const char *cctype, uint32 flags)
1176 {
1177         struct winbindd_request request;
1178         struct winbindd_response response;
1179         NSS_STATUS result;
1180         char *p;
1181         char *password;
1182
1183         /* Send off request */
1184
1185         ZERO_STRUCT(request);
1186         ZERO_STRUCT(response);
1187
1188         p = strchr(username, '%');
1189
1190         if (p) {
1191                 *p = 0;
1192                 fstrcpy(request.data.auth.user, username);
1193                 fstrcpy(request.data.auth.pass, p + 1);
1194                 *p = '%';
1195         } else {
1196                 fstrcpy(request.data.auth.user, username);
1197                 password = wbinfo_prompt_pass(NULL, username);
1198                 fstrcpy(request.data.auth.pass, password);
1199                 SAFE_FREE(password);
1200         }
1201
1202         request.flags = flags;
1203
1204         fstrcpy(request.data.auth.krb5_cc_type, cctype);
1205
1206         request.data.auth.uid = geteuid();
1207
1208         result = winbindd_request_response(WINBINDD_PAM_AUTH, &request, &response);
1209
1210         /* Display response */
1211
1212         d_printf("plaintext kerberos password authentication for [%s] %s (requesting cctype: %s)\n",
1213                 username, (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed", cctype);
1214
1215         if (response.data.auth.nt_status)
1216                 d_fprintf(stderr, "error code was %s (0x%x)\nerror messsage was: %s\n",
1217                          response.data.auth.nt_status_string,
1218                          response.data.auth.nt_status,
1219                          response.data.auth.error_string);
1220
1221         if (result == NSS_STATUS_SUCCESS) {
1222
1223                 if (request.flags & WBFLAG_PAM_INFO3_TEXT) {
1224                         if (response.data.auth.info3.user_flgs & NETLOGON_CACHED_ACCOUNT) {
1225                                 d_printf("user_flgs: NETLOGON_CACHED_ACCOUNT\n");
1226                         }
1227                 }
1228
1229                 if (response.data.auth.krb5ccname[0] != '\0') {
1230                         d_printf("credentials were put in: %s\n", response.data.auth.krb5ccname);
1231                 } else {
1232                         d_printf("no credentials cached\n");
1233                 }
1234         }
1235
1236         return result == NSS_STATUS_SUCCESS;
1237 }
1238
1239 /* Authenticate a user with a plaintext password */
1240
1241 static bool wbinfo_auth(char *username)
1242 {
1243         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
1244         char *s = NULL;
1245         char *p = NULL;
1246         char *password = NULL;
1247         char *name = NULL;
1248
1249         if ((s = SMB_STRDUP(username)) == NULL) {
1250                 return false;
1251         }
1252
1253         if ((p = strchr(s, '%')) != NULL) {
1254                 *p = 0;
1255                 p++;
1256                 password = SMB_STRDUP(p);
1257         } else {
1258                 password = wbinfo_prompt_pass(NULL, username);
1259         }
1260
1261         name = s;
1262
1263         wbc_status = wbcAuthenticateUser(name, password);
1264
1265         d_printf("plaintext password authentication %s\n",
1266                  WBC_ERROR_IS_OK(wbc_status) ? "succeeded" : "failed");
1267
1268 #if 0
1269         if (response.data.auth.nt_status)
1270                 d_fprintf(stderr, "error code was %s (0x%x)\nerror messsage was: %s\n",
1271                          response.data.auth.nt_status_string,
1272                          response.data.auth.nt_status,
1273                          response.data.auth.error_string);
1274 #endif
1275
1276         SAFE_FREE(s);
1277         SAFE_FREE(password);
1278
1279         return WBC_ERROR_IS_OK(wbc_status);
1280 }
1281
1282 /* Authenticate a user with a challenge/response */
1283
1284 static bool wbinfo_auth_crap(char *username)
1285 {
1286         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
1287         struct wbcAuthUserParams params;
1288         struct wbcAuthUserInfo *info = NULL;
1289         struct wbcAuthErrorInfo *err = NULL;
1290         DATA_BLOB lm = data_blob_null;
1291         DATA_BLOB nt = data_blob_null;
1292         fstring name_user;
1293         fstring name_domain;
1294         char *pass;
1295         char *p;
1296
1297         p = strchr(username, '%');
1298
1299         if (p) {
1300                 *p = 0;
1301                 pass = SMB_STRDUP(p + 1);
1302         } else {
1303                 pass = wbinfo_prompt_pass(NULL, username);
1304         }
1305
1306         parse_wbinfo_domain_user(username, name_domain, name_user);
1307
1308         params.account_name     = name_user;
1309         params.domain_name      = name_domain;
1310         params.workstation_name = NULL;
1311
1312         params.flags            = 0;
1313         params.parameter_control= WBC_MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT |
1314                                   WBC_MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT;
1315
1316         params.level            = WBC_AUTH_USER_LEVEL_RESPONSE;
1317
1318         generate_random_buffer(params.password.response.challenge, 8);
1319
1320         if (lp_client_ntlmv2_auth()) {
1321                 DATA_BLOB server_chal;
1322                 DATA_BLOB names_blob;
1323
1324                 server_chal = data_blob(params.password.response.challenge, 8);
1325
1326                 /* Pretend this is a login to 'us', for blob purposes */
1327                 names_blob = NTLMv2_generate_names_blob(NULL, global_myname(), lp_workgroup());
1328
1329                 if (!SMBNTLMv2encrypt(NULL, name_user, name_domain, pass, &server_chal,
1330                                       &names_blob,
1331                                       &lm, &nt, NULL, NULL)) {
1332                         data_blob_free(&names_blob);
1333                         data_blob_free(&server_chal);
1334                         SAFE_FREE(pass);
1335                         return false;
1336                 }
1337                 data_blob_free(&names_blob);
1338                 data_blob_free(&server_chal);
1339
1340         } else {
1341                 if (lp_client_lanman_auth()) {
1342                         bool ok;
1343                         lm = data_blob(NULL, 24);
1344                         ok = SMBencrypt(pass, params.password.response.challenge,
1345                                         lm.data);
1346                         if (!ok) {
1347                                 data_blob_free(&lm);
1348                         }
1349                 }
1350                 nt = data_blob(NULL, 24);
1351                 SMBNTencrypt(pass, params.password.response.challenge,
1352                              nt.data);
1353         }
1354
1355         params.password.response.nt_length      = nt.length;
1356         params.password.response.nt_data        = nt.data;
1357         params.password.response.lm_length      = lm.length;
1358         params.password.response.lm_data        = lm.data;
1359
1360         wbc_status = wbcAuthenticateUserEx(&params, &info, &err);
1361
1362         /* Display response */
1363
1364         d_printf("challenge/response password authentication %s\n",
1365                  WBC_ERROR_IS_OK(wbc_status) ? "succeeded" : "failed");
1366
1367         if (wbc_status == WBC_ERR_AUTH_ERROR) {
1368                 d_fprintf(stderr, "error code was %s (0x%x)\nerror messsage was: %s\n",
1369                          err->nt_string,
1370                          err->nt_status,
1371                          err->display_string);
1372                 wbcFreeMemory(err);
1373         } else if (WBC_ERROR_IS_OK(wbc_status)) {
1374                 wbcFreeMemory(info);
1375         }
1376
1377         data_blob_free(&nt);
1378         data_blob_free(&lm);
1379         SAFE_FREE(pass);
1380
1381         return WBC_ERROR_IS_OK(wbc_status);
1382 }
1383
1384 /* Authenticate a user with a plaintext password and set a token */
1385
1386 static bool wbinfo_klog(char *username)
1387 {
1388         struct winbindd_request request;
1389         struct winbindd_response response;
1390         NSS_STATUS result;
1391         char *p;
1392
1393         /* Send off request */
1394
1395         ZERO_STRUCT(request);
1396         ZERO_STRUCT(response);
1397
1398         p = strchr(username, '%');
1399
1400         if (p) {
1401                 *p = 0;
1402                 fstrcpy(request.data.auth.user, username);
1403                 fstrcpy(request.data.auth.pass, p + 1);
1404                 *p = '%';
1405         } else {
1406                 fstrcpy(request.data.auth.user, username);
1407                 fstrcpy(request.data.auth.pass, getpass("Password: "));
1408         }
1409
1410         request.flags |= WBFLAG_PAM_AFS_TOKEN;
1411
1412         result = winbindd_request_response(WINBINDD_PAM_AUTH, &request, &response);
1413
1414         /* Display response */
1415
1416         d_printf("plaintext password authentication %s\n",
1417                  (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed");
1418
1419         if (response.data.auth.nt_status)
1420                 d_fprintf(stderr, "error code was %s (0x%x)\nerror messsage was: %s\n",
1421                          response.data.auth.nt_status_string,
1422                          response.data.auth.nt_status,
1423                          response.data.auth.error_string);
1424
1425         if (result != NSS_STATUS_SUCCESS)
1426                 return false;
1427
1428         if (response.extra_data.data == NULL) {
1429                 d_fprintf(stderr, "Did not get token data\n");
1430                 return false;
1431         }
1432
1433         if (!afs_settoken_str((char *)response.extra_data.data)) {
1434                 d_fprintf(stderr, "Could not set token\n");
1435                 return false;
1436         }
1437
1438         d_printf("Successfully created AFS token\n");
1439         return true;
1440 }
1441
1442 /* Print domain users */
1443
1444 static bool print_domain_users(const char *domain)
1445 {
1446         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
1447         uint32_t i;
1448         uint32_t num_users = 0;
1449         const char **users = NULL;
1450
1451         /* Send request to winbind daemon */
1452
1453         /* '.' is the special sign for our own domain */
1454         if (domain && strcmp(domain, ".") == 0) {
1455                 domain = get_winbind_domain();
1456         }
1457
1458         wbc_status = wbcListUsers(domain, &num_users, &users);
1459         if (!WBC_ERROR_IS_OK(wbc_status)) {
1460                 return false;
1461         }
1462
1463         for (i=0; i < num_users; i++) {
1464                 d_printf("%s\n", users[i]);
1465         }
1466
1467         wbcFreeMemory(users);
1468
1469         return true;
1470 }
1471
1472 /* Print domain groups */
1473
1474 static bool print_domain_groups(const char *domain)
1475 {
1476         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
1477         uint32_t i;
1478         uint32_t num_groups = 0;
1479         const char **groups = NULL;
1480
1481         /* Send request to winbind daemon */
1482
1483         /* '.' is the special sign for our own domain */
1484         if (domain && strcmp(domain, ".") == 0) {
1485                 domain = get_winbind_domain();
1486         }
1487
1488         wbc_status = wbcListGroups(domain, &num_groups, &groups);
1489         if (!WBC_ERROR_IS_OK(wbc_status)) {
1490                 return false;
1491         }
1492
1493         for (i=0; i < num_groups; i++) {
1494                 d_printf("%s\n", groups[i]);
1495         }
1496
1497         wbcFreeMemory(groups);
1498
1499         return true;
1500 }
1501
1502 /* Set the authorised user for winbindd access in secrets.tdb */
1503
1504 static bool wbinfo_set_auth_user(char *username)
1505 {
1506         const char *password;
1507         char *p;
1508         fstring user, domain;
1509
1510         /* Separate into user and password */
1511
1512         parse_wbinfo_domain_user(username, domain, user);
1513
1514         p = strchr(user, '%');
1515
1516         if (p != NULL) {
1517                 *p = 0;
1518                 password = p+1;
1519         } else {
1520                 char *thepass = getpass("Password: ");
1521                 if (thepass) {
1522                         password = thepass;
1523                 } else
1524                         password = "";
1525         }
1526
1527         /* Store or remove DOMAIN\username%password in secrets.tdb */
1528
1529         secrets_init();
1530
1531         if (user[0]) {
1532
1533                 if (!secrets_store(SECRETS_AUTH_USER, user,
1534                                    strlen(user) + 1)) {
1535                         d_fprintf(stderr, "error storing username\n");
1536                         return false;
1537                 }
1538
1539                 /* We always have a domain name added by the
1540                    parse_wbinfo_domain_user() function. */
1541
1542                 if (!secrets_store(SECRETS_AUTH_DOMAIN, domain,
1543                                    strlen(domain) + 1)) {
1544                         d_fprintf(stderr, "error storing domain name\n");
1545                         return false;
1546                 }
1547
1548         } else {
1549                 secrets_delete(SECRETS_AUTH_USER);
1550                 secrets_delete(SECRETS_AUTH_DOMAIN);
1551         }
1552
1553         if (password[0]) {
1554
1555                 if (!secrets_store(SECRETS_AUTH_PASSWORD, password,
1556                                    strlen(password) + 1)) {
1557                         d_fprintf(stderr, "error storing password\n");
1558                         return false;
1559                 }
1560
1561         } else
1562                 secrets_delete(SECRETS_AUTH_PASSWORD);
1563
1564         return true;
1565 }
1566
1567 static void wbinfo_get_auth_user(void)
1568 {
1569         char *user, *domain, *password;
1570
1571         /* Lift data from secrets file */
1572
1573         secrets_fetch_ipc_userpass(&user, &domain, &password);
1574
1575         if ((!user || !*user) && (!domain || !*domain ) && (!password || !*password)){
1576
1577                 SAFE_FREE(user);
1578                 SAFE_FREE(domain);
1579                 SAFE_FREE(password);
1580                 d_printf("No authorised user configured\n");
1581                 return;
1582         }
1583
1584         /* Pretty print authorised user info */
1585
1586         d_printf("%s%s%s%s%s\n", domain ? domain : "", domain ? lp_winbind_separator(): "",
1587                  user, password ? "%" : "", password ? password : "");
1588
1589         SAFE_FREE(user);
1590         SAFE_FREE(domain);
1591         SAFE_FREE(password);
1592 }
1593
1594 static bool wbinfo_ping(void)
1595 {
1596         wbcErr wbc_status;
1597
1598         wbc_status = wbcPing();
1599
1600         /* Display response */
1601
1602         d_printf("Ping to winbindd %s\n",
1603                  WBC_ERROR_IS_OK(wbc_status) ? "succeeded" : "failed");
1604
1605         return WBC_ERROR_IS_OK(wbc_status);
1606 }
1607
1608 static bool wbinfo_change_user_password(const char *username)
1609 {
1610         wbcErr wbc_status;
1611         char *old_password = NULL;
1612         char *new_password = NULL;
1613
1614         old_password = wbinfo_prompt_pass("old", username);
1615         new_password = wbinfo_prompt_pass("new", username);
1616
1617         wbc_status = wbcChangeUserPassword(username, old_password, new_password);
1618
1619         /* Display response */
1620
1621         d_printf("Password change for user %s %s\n", username,
1622                 WBC_ERROR_IS_OK(wbc_status) ? "succeeded" : "failed");
1623
1624         SAFE_FREE(old_password);
1625         SAFE_FREE(new_password);
1626
1627         return WBC_ERROR_IS_OK(wbc_status);
1628 }
1629
1630 /* Main program */
1631
1632 enum {
1633         OPT_SET_AUTH_USER = 1000,
1634         OPT_GET_AUTH_USER,
1635         OPT_DOMAIN_NAME,
1636         OPT_SEQUENCE,
1637         OPT_GETDCNAME,
1638         OPT_DSGETDCNAME,
1639         OPT_USERDOMGROUPS,
1640         OPT_SIDALIASES,
1641         OPT_USERSIDS,
1642         OPT_ALLOCATE_UID,
1643         OPT_ALLOCATE_GID,
1644         OPT_SET_UID_MAPPING,
1645         OPT_SET_GID_MAPPING,
1646         OPT_REMOVE_UID_MAPPING,
1647         OPT_REMOVE_GID_MAPPING,
1648         OPT_SEPARATOR,
1649         OPT_LIST_ALL_DOMAINS,
1650         OPT_LIST_OWN_DOMAIN,
1651         OPT_UID_INFO,
1652         OPT_USER_SIDINFO,
1653         OPT_GROUP_INFO,
1654         OPT_GID_INFO,
1655         OPT_VERBOSE,
1656         OPT_ONLINESTATUS,
1657         OPT_CHANGE_USER_PASSWORD,
1658         OPT_SID_TO_FULLNAME
1659 };
1660
1661 int main(int argc, char **argv, char **envp)
1662 {
1663         int opt;
1664         TALLOC_CTX *frame = talloc_stackframe();
1665         poptContext pc;
1666         static char *string_arg;
1667         char *string_subarg = NULL;
1668         static char *opt_domain_name;
1669         static int int_arg;
1670         int int_subarg = -1;
1671         int result = 1;
1672         bool verbose = false;
1673
1674         struct poptOption long_options[] = {
1675                 POPT_AUTOHELP
1676
1677                 /* longName, shortName, argInfo, argPtr, value, descrip,
1678                    argDesc */
1679
1680                 { "domain-users", 'u', POPT_ARG_NONE, 0, 'u', "Lists all domain users", "domain"},
1681                 { "domain-groups", 'g', POPT_ARG_NONE, 0, 'g', "Lists all domain groups", "domain" },
1682                 { "WINS-by-name", 'N', POPT_ARG_STRING, &string_arg, 'N', "Converts NetBIOS name to IP", "NETBIOS-NAME" },
1683                 { "WINS-by-ip", 'I', POPT_ARG_STRING, &string_arg, 'I', "Converts IP address to NetBIOS name", "IP" },
1684                 { "name-to-sid", 'n', POPT_ARG_STRING, &string_arg, 'n', "Converts name to sid", "NAME" },
1685                 { "sid-to-name", 's', POPT_ARG_STRING, &string_arg, 's', "Converts sid to name", "SID" },
1686                 { "sid-to-fullname", 0, POPT_ARG_STRING, &string_arg,
1687                   OPT_SID_TO_FULLNAME, "Converts sid to fullname", "SID" },
1688                 { "lookup-rids", 'R', POPT_ARG_STRING, &string_arg, 'R', "Converts RIDs to names", "RIDs" },
1689                 { "uid-to-sid", 'U', POPT_ARG_INT, &int_arg, 'U', "Converts uid to sid" , "UID" },
1690                 { "gid-to-sid", 'G', POPT_ARG_INT, &int_arg, 'G', "Converts gid to sid", "GID" },
1691                 { "sid-to-uid", 'S', POPT_ARG_STRING, &string_arg, 'S', "Converts sid to uid", "SID" },
1692                 { "sid-to-gid", 'Y', POPT_ARG_STRING, &string_arg, 'Y', "Converts sid to gid", "SID" },
1693                 { "allocate-uid", 0, POPT_ARG_NONE, 0, OPT_ALLOCATE_UID,
1694                   "Get a new UID out of idmap" },
1695                 { "allocate-gid", 0, POPT_ARG_NONE, 0, OPT_ALLOCATE_GID,
1696                   "Get a new GID out of idmap" },
1697                 { "set-uid-mapping", 0, POPT_ARG_STRING, &string_arg, OPT_SET_UID_MAPPING, "Create or modify uid to sid mapping in idmap", "UID,SID" },
1698                 { "set-gid-mapping", 0, POPT_ARG_STRING, &string_arg, OPT_SET_GID_MAPPING, "Create or modify gid to sid mapping in idmap", "GID,SID" },
1699                 { "remove-uid-mapping", 0, POPT_ARG_STRING, &string_arg, OPT_REMOVE_UID_MAPPING, "Remove uid to sid mapping in idmap", "UID,SID" },
1700                 { "remove-gid-mapping", 0, POPT_ARG_STRING, &string_arg, OPT_REMOVE_GID_MAPPING, "Remove gid to sid mapping in idmap", "GID,SID" },
1701                 { "check-secret", 't', POPT_ARG_NONE, 0, 't', "Check shared secret" },
1702                 { "trusted-domains", 'm', POPT_ARG_NONE, 0, 'm', "List trusted domains" },
1703                 { "all-domains", 0, POPT_ARG_NONE, 0, OPT_LIST_ALL_DOMAINS, "List all domains (trusted and own domain)" },
1704                 { "own-domain", 0, POPT_ARG_NONE, 0, OPT_LIST_OWN_DOMAIN, "List own domain" },
1705                 { "sequence", 0, POPT_ARG_NONE, 0, OPT_SEQUENCE, "Show sequence numbers of all domains" },
1706                 { "online-status", 0, POPT_ARG_NONE, 0, OPT_ONLINESTATUS, "Show whether domains are marked as online or offline"},
1707                 { "domain-info", 'D', POPT_ARG_STRING, &string_arg, 'D', "Show most of the info we have about the domain" },
1708                 { "user-info", 'i', POPT_ARG_STRING, &string_arg, 'i', "Get user info", "USER" },
1709                 { "uid-info", 0, POPT_ARG_INT, &int_arg, OPT_UID_INFO, "Get user info from uid", "UID" },
1710                 { "group-info", 0, POPT_ARG_STRING, &string_arg, OPT_GROUP_INFO, "Get group info", "GROUP" },
1711                 { "user-sidinfo", 0, POPT_ARG_STRING, &string_arg, OPT_USER_SIDINFO, "Get user info from sid", "SID" },
1712                 { "gid-info", 0, POPT_ARG_INT, &int_arg, OPT_GID_INFO, "Get group info from gid", "GID" },
1713                 { "user-groups", 'r', POPT_ARG_STRING, &string_arg, 'r', "Get user groups", "USER" },
1714                 { "user-domgroups", 0, POPT_ARG_STRING, &string_arg,
1715                   OPT_USERDOMGROUPS, "Get user domain groups", "SID" },
1716                 { "sid-aliases", 0, POPT_ARG_STRING, &string_arg, OPT_SIDALIASES, "Get sid aliases", "SID" },
1717                 { "user-sids", 0, POPT_ARG_STRING, &string_arg, OPT_USERSIDS, "Get user group sids for user SID", "SID" },
1718                 { "authenticate", 'a', POPT_ARG_STRING, &string_arg, 'a', "authenticate user", "user%password" },
1719                 { "set-auth-user", 0, POPT_ARG_STRING, &string_arg, OPT_SET_AUTH_USER, "Store user and password used by winbindd (root only)", "user%password" },
1720                 { "getdcname", 0, POPT_ARG_STRING, &string_arg, OPT_GETDCNAME,
1721                   "Get a DC name for a foreign domain", "domainname" },
1722                 { "dsgetdcname", 0, POPT_ARG_STRING, &string_arg, OPT_DSGETDCNAME, "Find a DC for a domain", "domainname" },
1723                 { "get-auth-user", 0, POPT_ARG_NONE, NULL, OPT_GET_AUTH_USER, "Retrieve user and password used by winbindd (root only)", NULL },
1724                 { "ping", 'p', POPT_ARG_NONE, 0, 'p', "Ping winbindd to see if it is alive" },
1725                 { "domain", 0, POPT_ARG_STRING, &opt_domain_name, OPT_DOMAIN_NAME, "Define to the domain to restrict operation", "domain" },
1726 #ifdef WITH_FAKE_KASERVER
1727                 { "klog", 'k', POPT_ARG_STRING, &string_arg, 'k', "set an AFS token from winbind", "user%password" },
1728 #endif
1729 #ifdef HAVE_KRB5
1730                 { "krb5auth", 'K', POPT_ARG_STRING, &string_arg, 'K', "authenticate user using Kerberos", "user%password" },
1731                         /* destroys wbinfo --help output */
1732                         /* "user%password,DOM\\user%password,user@EXAMPLE.COM,EXAMPLE.COM\\user%password" }, */
1733 #endif
1734                 { "separator", 0, POPT_ARG_NONE, 0, OPT_SEPARATOR, "Get the active winbind separator", NULL },
1735                 { "verbose", 0, POPT_ARG_NONE, 0, OPT_VERBOSE, "Print additional information per command", NULL },
1736                 { "change-user-password", 0, POPT_ARG_STRING, &string_arg, OPT_CHANGE_USER_PASSWORD, "Change the password for a user", NULL },
1737                 POPT_COMMON_CONFIGFILE
1738                 POPT_COMMON_VERSION
1739                 POPT_TABLEEND
1740         };
1741
1742         /* Samba client initialisation */
1743         load_case_tables();
1744
1745
1746         /* Parse options */
1747
1748         pc = poptGetContext("wbinfo", argc, (const char **)argv, long_options, 0);
1749
1750         /* Parse command line options */
1751
1752         if (argc == 1) {
1753                 poptPrintHelp(pc, stderr, 0);
1754                 return 1;
1755         }
1756
1757         while((opt = poptGetNextOpt(pc)) != -1) {
1758                 /* get the generic configuration parameters like --domain */
1759                 switch (opt) {
1760                 case OPT_VERBOSE:
1761                         verbose = True;
1762                         break;
1763                 }
1764         }
1765
1766         poptFreeContext(pc);
1767
1768         if (!lp_load(get_dyn_CONFIGFILE(), true, false, false, true)) {
1769                 d_fprintf(stderr, "wbinfo: error opening config file %s. Error was %s\n",
1770                         get_dyn_CONFIGFILE(), strerror(errno));
1771                 exit(1);
1772         }
1773
1774         if (!init_names())
1775                 return 1;
1776
1777         load_interfaces();
1778
1779         pc = poptGetContext(NULL, argc, (const char **)argv, long_options,
1780                             POPT_CONTEXT_KEEP_FIRST);
1781
1782         while((opt = poptGetNextOpt(pc)) != -1) {
1783                 switch (opt) {
1784                 case 'u':
1785                         if (!print_domain_users(opt_domain_name)) {
1786                                 d_fprintf(stderr, "Error looking up domain users\n");
1787                                 goto done;
1788                         }
1789                         break;
1790                 case 'g':
1791                         if (!print_domain_groups(opt_domain_name)) {
1792                                 d_fprintf(stderr, "Error looking up domain groups\n");
1793                                 goto done;
1794                         }
1795                         break;
1796                 case 's':
1797                         if (!wbinfo_lookupsid(string_arg)) {
1798                                 d_fprintf(stderr, "Could not lookup sid %s\n", string_arg);
1799                                 goto done;
1800                         }
1801                         break;
1802                 case OPT_SID_TO_FULLNAME:
1803                         if (!wbinfo_lookupsid_fullname(string_arg)) {
1804                                 d_fprintf(stderr, "Could not lookup sid %s\n",
1805                                           string_arg);
1806                                 goto done;
1807                         }
1808                         break;
1809                 case 'R':
1810                         if (!wbinfo_lookuprids(opt_domain_name, string_arg)) {
1811                                 d_fprintf(stderr, "Could not lookup RIDs %s\n", string_arg);
1812                                 goto done;
1813                         }
1814                         break;
1815                 case 'n':
1816                         if (!wbinfo_lookupname(string_arg)) {
1817                                 d_fprintf(stderr, "Could not lookup name %s\n", string_arg);
1818                                 goto done;
1819                         }
1820                         break;
1821                 case 'N':
1822                         if (!wbinfo_wins_byname(string_arg)) {
1823                                 d_fprintf(stderr, "Could not lookup WINS by name %s\n", string_arg);
1824                                 goto done;
1825                         }
1826                         break;
1827                 case 'I':
1828                         if (!wbinfo_wins_byip(string_arg)) {
1829                                 d_fprintf(stderr, "Could not lookup WINS by IP %s\n", string_arg);
1830                                 goto done;
1831                         }
1832                         break;
1833                 case 'U':
1834                         if (!wbinfo_uid_to_sid(int_arg)) {
1835                                 d_fprintf(stderr, "Could not convert uid %d to sid\n", int_arg);
1836                                 goto done;
1837                         }
1838                         break;
1839                 case 'G':
1840                         if (!wbinfo_gid_to_sid(int_arg)) {
1841                                 d_fprintf(stderr, "Could not convert gid %d to sid\n",
1842                                        int_arg);
1843                                 goto done;
1844                         }
1845                         break;
1846                 case 'S':
1847                         if (!wbinfo_sid_to_uid(string_arg)) {
1848                                 d_fprintf(stderr, "Could not convert sid %s to uid\n",
1849                                        string_arg);
1850                                 goto done;
1851                         }
1852                         break;
1853                 case 'Y':
1854                         if (!wbinfo_sid_to_gid(string_arg)) {
1855                                 d_fprintf(stderr, "Could not convert sid %s to gid\n",
1856                                        string_arg);
1857                                 goto done;
1858                         }
1859                         break;
1860                 case OPT_ALLOCATE_UID:
1861                         if (!wbinfo_allocate_uid()) {
1862                                 d_fprintf(stderr, "Could not allocate a uid\n");
1863                                 goto done;
1864                         }
1865                         break;
1866                 case OPT_ALLOCATE_GID:
1867                         if (!wbinfo_allocate_gid()) {
1868                                 d_fprintf(stderr, "Could not allocate a gid\n");
1869                                 goto done;
1870                         }
1871                         break;
1872                 case OPT_SET_UID_MAPPING:
1873                         if (!parse_mapping_arg(string_arg, &int_subarg,
1874                                 &string_subarg) ||
1875                             !wbinfo_set_uid_mapping(int_subarg, string_subarg))
1876                         {
1877                                 d_fprintf(stderr, "Could not create or modify "
1878                                           "uid to sid mapping\n");
1879                                 goto done;
1880                         }
1881                         break;
1882                 case OPT_SET_GID_MAPPING:
1883                         if (!parse_mapping_arg(string_arg, &int_subarg,
1884                                 &string_subarg) ||
1885                             !wbinfo_set_gid_mapping(int_subarg, string_subarg))
1886                         {
1887                                 d_fprintf(stderr, "Could not create or modify "
1888                                           "gid to sid mapping\n");
1889                                 goto done;
1890                         }
1891                         break;
1892                 case OPT_REMOVE_UID_MAPPING:
1893                         if (!parse_mapping_arg(string_arg, &int_subarg,
1894                                 &string_subarg) ||
1895                             !wbinfo_remove_uid_mapping(int_subarg,
1896                                 string_subarg))
1897                         {
1898                                 d_fprintf(stderr, "Could not remove uid to sid "
1899                                     "mapping\n");
1900                                 goto done;
1901                         }
1902                         break;
1903                 case OPT_REMOVE_GID_MAPPING:
1904                         if (!parse_mapping_arg(string_arg, &int_subarg,
1905                                 &string_subarg) ||
1906                             !wbinfo_remove_gid_mapping(int_subarg,
1907                                 string_subarg))
1908                         {
1909                                 d_fprintf(stderr, "Could not remove gid to sid "
1910                                     "mapping\n");
1911                                 goto done;
1912                         }
1913                         break;
1914                 case 't':
1915                         if (!wbinfo_check_secret()) {
1916                                 d_fprintf(stderr, "Could not check secret\n");
1917                                 goto done;
1918                         }
1919                         break;
1920                 case 'm':
1921                         if (!wbinfo_list_domains(false, verbose)) {
1922                                 d_fprintf(stderr, "Could not list trusted domains\n");
1923                                 goto done;
1924                         }
1925                         break;
1926                 case OPT_SEQUENCE:
1927                         if (!wbinfo_show_sequence(opt_domain_name)) {
1928                                 d_fprintf(stderr, "Could not show sequence numbers\n");
1929                                 goto done;
1930                         }
1931                         break;
1932                 case OPT_ONLINESTATUS:
1933                         if (!wbinfo_show_onlinestatus(opt_domain_name)) {
1934                                 d_fprintf(stderr, "Could not show online-status\n");
1935                                 goto done;
1936                         }
1937                         break;
1938                 case 'D':
1939                         if (!wbinfo_domain_info(string_arg)) {
1940                                 d_fprintf(stderr, "Could not get domain info\n");
1941                                 goto done;
1942                         }
1943                         break;
1944                 case 'i':
1945                         if (!wbinfo_get_userinfo(string_arg)) {
1946                                 d_fprintf(stderr, "Could not get info for user %s\n",
1947                                                   string_arg);
1948                                 goto done;
1949                         }
1950                         break;
1951                 case OPT_USER_SIDINFO:
1952                         if ( !wbinfo_get_user_sidinfo(string_arg)) {
1953                                 d_fprintf(stderr, "Could not get info for user sid %s\n",
1954                                     string_arg);
1955                                 goto done;
1956                         }
1957                         break;
1958                 case OPT_UID_INFO:
1959                         if ( !wbinfo_get_uidinfo(int_arg)) {
1960                                 d_fprintf(stderr, "Could not get info for uid "
1961                                                 "%d\n", int_arg);
1962                                 goto done;
1963                         }
1964                         break;
1965                 case OPT_GROUP_INFO:
1966                         if ( !wbinfo_get_groupinfo(string_arg)) {
1967                                 d_fprintf(stderr, "Could not get info for "
1968                                           "group %s\n", string_arg);
1969                                 goto done;
1970                         }
1971                         break;
1972                 case OPT_GID_INFO:
1973                         if ( !wbinfo_get_gidinfo(int_arg)) {
1974                                 d_fprintf(stderr, "Could not get info for gid "
1975                                                 "%d\n", int_arg);
1976                                 goto done;
1977                         }
1978                         break;
1979                 case 'r':
1980                         if (!wbinfo_get_usergroups(string_arg)) {
1981                                 d_fprintf(stderr, "Could not get groups for user %s\n",
1982                                        string_arg);
1983                                 goto done;
1984                         }
1985                         break;
1986                 case OPT_USERSIDS:
1987                         if (!wbinfo_get_usersids(string_arg)) {
1988                                 d_fprintf(stderr, "Could not get group SIDs for user SID %s\n",
1989                                        string_arg);
1990                                 goto done;
1991                         }
1992                         break;
1993                 case OPT_USERDOMGROUPS:
1994                         if (!wbinfo_get_userdomgroups(string_arg)) {
1995                                 d_fprintf(stderr, "Could not get user's domain groups "
1996                                          "for user SID %s\n", string_arg);
1997                                 goto done;
1998                         }
1999                         break;
2000                 case OPT_SIDALIASES:
2001                         if (!wbinfo_get_sidaliases(opt_domain_name, string_arg)) {
2002                                 d_fprintf(stderr, "Could not get sid aliases "
2003                                          "for user SID %s\n", string_arg);
2004                                 goto done;
2005                         }
2006                         break;
2007                 case 'a': {
2008                                 bool got_error = false;
2009
2010                                 if (!wbinfo_auth(string_arg)) {
2011                                         d_fprintf(stderr, "Could not authenticate user %s with "
2012                                                 "plaintext password\n", string_arg);
2013                                         got_error = true;
2014                                 }
2015
2016                                 if (!wbinfo_auth_crap(string_arg)) {
2017                                         d_fprintf(stderr, "Could not authenticate user %s with "
2018                                                 "challenge/response\n", string_arg);
2019                                         got_error = true;
2020                                 }
2021
2022                                 if (got_error)
2023                                         goto done;
2024                                 break;
2025                         }
2026                 case 'K': {
2027                                 uint32 flags =  WBFLAG_PAM_KRB5 |
2028                                                 WBFLAG_PAM_CACHED_LOGIN |
2029                                                 WBFLAG_PAM_FALLBACK_AFTER_KRB5 |
2030                                                 WBFLAG_PAM_INFO3_TEXT;
2031
2032                                 if (!wbinfo_auth_krb5(string_arg, "FILE", flags)) {
2033                                         d_fprintf(stderr, "Could not authenticate user [%s] with "
2034                                                 "Kerberos (ccache: %s)\n", string_arg, "FILE");
2035                                         goto done;
2036                                 }
2037                                 break;
2038                         }
2039                 case 'k':
2040                         if (!wbinfo_klog(string_arg)) {
2041                                 d_fprintf(stderr, "Could not klog user\n");
2042                                 goto done;
2043                         }
2044                         break;
2045                 case 'p':
2046                         if (!wbinfo_ping()) {
2047                                 d_fprintf(stderr, "could not ping winbindd!\n");
2048                                 goto done;
2049                         }
2050                         break;
2051                 case OPT_SET_AUTH_USER:
2052                         if (!wbinfo_set_auth_user(string_arg)) {
2053                                 goto done;
2054                         }
2055                         break;
2056                 case OPT_GET_AUTH_USER:
2057                         wbinfo_get_auth_user();
2058                         break;
2059                 case OPT_GETDCNAME:
2060                         if (!wbinfo_getdcname(string_arg)) {
2061                                 goto done;
2062                         }
2063                         break;
2064                 case OPT_DSGETDCNAME:
2065                         if (!wbinfo_dsgetdcname(string_arg, 0)) {
2066                                 goto done;
2067                         }
2068                         break;
2069                 case OPT_SEPARATOR: {
2070                         const char sep = winbind_separator_int(true);
2071                         if ( !sep ) {
2072                                 goto done;
2073                         }
2074                         d_printf("%c\n", sep);
2075                         break;
2076                 }
2077                 case OPT_LIST_ALL_DOMAINS:
2078                         if (!wbinfo_list_domains(true, verbose)) {
2079                                 goto done;
2080                         }
2081                         break;
2082                 case OPT_LIST_OWN_DOMAIN:
2083                         if (!wbinfo_list_own_domain()) {
2084                                 goto done;
2085                         }
2086                         break;
2087                 case OPT_CHANGE_USER_PASSWORD:
2088                         if (!wbinfo_change_user_password(string_arg)) {
2089                                 d_fprintf(stderr, "Could not change user password "
2090                                          "for user %s\n", string_arg);
2091                                 goto done;
2092                         }
2093                         break;
2094
2095                 /* generic configuration options */
2096                 case OPT_DOMAIN_NAME:
2097                         break;
2098                 case OPT_VERBOSE:
2099                         break;
2100                 default:
2101                         d_fprintf(stderr, "Invalid option\n");
2102                         poptPrintHelp(pc, stderr, 0);
2103                         goto done;
2104                 }
2105         }
2106
2107         result = 0;
2108
2109         /* Exit code */
2110
2111  done:
2112         talloc_destroy(frame);
2113
2114         poptFreeContext(pc);
2115         return result;
2116 }