r25181: sync winbind client code with samba3
[jra/samba/.git] / source4 / 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-2007
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 "pstring.h"
25 #include "winbind_client.h"
26 #include "librpc/gen_ndr/ndr_netlogon.h"
27 #include "libcli/auth/libcli_auth.h"
28 #include "libcli/security/security.h"
29 #include "lib/cmdline/popt_common.h"
30 #include "dynconfig.h"
31 #include "param/param.h"
32
33 extern int winbindd_fd;
34
35 static char winbind_separator_int(BOOL strict)
36 {
37         struct winbindd_response response;
38         static BOOL got_sep;
39         static char sep;
40
41         if (got_sep)
42                 return sep;
43
44         ZERO_STRUCT(response);
45
46         /* Send off request */
47
48         if (winbindd_request_response(WINBINDD_INFO, NULL, &response) !=
49             NSS_STATUS_SUCCESS) {
50                 d_fprintf(stderr, "could not obtain winbind separator!\n");
51                 if (strict) {
52                         return 0;
53                 }
54                 /* HACK: (this module should not call lp_ funtions) */
55                 return *lp_winbind_separator();
56         }
57
58         sep = response.data.info.winbind_separator;
59         got_sep = True;
60
61         if (!sep) {
62                 d_fprintf(stderr, "winbind separator was NULL!\n");
63                 if (strict) {
64                         return 0;
65                 }
66                 /* HACK: (this module should not call lp_ funtions) */
67                 sep = *lp_winbind_separator();
68         }
69         
70         return sep;
71 }
72
73 static char winbind_separator(void)
74 {
75         return winbind_separator_int(False);
76 }
77
78 static const char *get_winbind_domain(void)
79 {
80         struct winbindd_response response;
81         static fstring winbind_domain;
82
83         ZERO_STRUCT(response);
84
85         /* Send off request */
86
87         if (winbindd_request_response(WINBINDD_DOMAIN_NAME, NULL, &response) !=
88             NSS_STATUS_SUCCESS) {
89                 d_fprintf(stderr, "could not obtain winbind domain name!\n");
90                 
91                 /* HACK: (this module should not call lp_ funtions) */
92                 return lp_workgroup();
93         }
94
95         fstrcpy(winbind_domain, response.data.domain_name);
96
97         return winbind_domain;
98
99 }
100
101 /* Copy of parse_domain_user from winbindd_util.c.  Parse a string of the
102    form DOMAIN/user into a domain and a user */
103
104 static BOOL parse_wbinfo_domain_user(const char *domuser, fstring domain, 
105                                      fstring user)
106 {
107
108         char *p = strchr(domuser,winbind_separator());
109
110         if (!p) {
111                 fstrcpy(user, domuser);
112                 fstrcpy(domain, get_winbind_domain());
113                 return True;
114         }
115         
116         fstrcpy(user, p+1);
117         fstrcpy(domain, domuser);
118         domain[PTR_DIFF(p, domuser)] = 0;
119         strupper_m(domain);
120
121         return True;
122 }
123
124 /* pull pwent info for a given user */
125
126 static BOOL wbinfo_get_userinfo(char *user)
127 {
128         struct winbindd_request request;
129         struct winbindd_response response;
130         NSS_STATUS result;
131         
132         ZERO_STRUCT(request);
133         ZERO_STRUCT(response);
134
135         /* Send request */
136         
137         fstrcpy(request.data.username, user);
138
139         result = winbindd_request_response(WINBINDD_GETPWNAM, &request, &response);
140         
141         if (result != NSS_STATUS_SUCCESS)
142                 return False;
143         
144         d_printf( "%s:%s:%d:%d:%s:%s:%s\n",
145                           response.data.pw.pw_name,
146                           response.data.pw.pw_passwd,
147                           response.data.pw.pw_uid,
148                           response.data.pw.pw_gid,
149                           response.data.pw.pw_gecos,
150                           response.data.pw.pw_dir,
151                           response.data.pw.pw_shell );
152         
153         return True;
154 }
155
156 /* pull pwent info for a given uid */
157 static BOOL wbinfo_get_uidinfo(int uid)
158 {
159         struct winbindd_request request;
160         struct winbindd_response response;
161         NSS_STATUS result;
162
163         ZERO_STRUCT(request);
164         ZERO_STRUCT(response);
165
166         request.data.uid = uid;
167
168         result = winbindd_request_response(WINBINDD_GETPWUID, &request, &response);
169
170         if (result != NSS_STATUS_SUCCESS)
171                 return False;
172
173         d_printf( "%s:%s:%d:%d:%s:%s:%s\n",
174                 response.data.pw.pw_name,
175                 response.data.pw.pw_passwd,
176                 response.data.pw.pw_uid,
177                 response.data.pw.pw_gid,
178                 response.data.pw.pw_gecos,
179                 response.data.pw.pw_dir,
180                 response.data.pw.pw_shell );
181
182         return True;
183 }
184
185 /* pull grent for a given group */
186 static BOOL wbinfo_get_groupinfo(char *group)
187 {
188         struct winbindd_request request;
189         struct winbindd_response response;
190         NSS_STATUS result;
191
192         ZERO_STRUCT(request);
193         ZERO_STRUCT(response);
194
195         /* Send request */
196
197         fstrcpy(request.data.groupname, group);
198
199         result = winbindd_request_response(WINBINDD_GETGRNAM, &request,
200                                   &response);
201
202         if ( result != NSS_STATUS_SUCCESS)
203                 return False;
204
205         d_printf( "%s:%s:%d\n",
206                   response.data.gr.gr_name,
207                   response.data.gr.gr_passwd,
208                   response.data.gr.gr_gid );
209         
210         return True;
211 }
212
213 /* List groups a user is a member of */
214
215 static BOOL wbinfo_get_usergroups(char *user)
216 {
217         struct winbindd_request request;
218         struct winbindd_response response;
219         NSS_STATUS result;
220         int i;
221         
222         ZERO_STRUCT(request);
223         ZERO_STRUCT(response);
224
225         /* Send request */
226
227         fstrcpy(request.data.username, user);
228
229         result = winbindd_request_response(WINBINDD_GETGROUPS, &request, &response);
230
231         if (result != NSS_STATUS_SUCCESS)
232                 return False;
233
234         for (i = 0; i < response.data.num_entries; i++)
235                 d_printf("%d\n", (int)((gid_t *)response.extra_data.data)[i]);
236
237         SAFE_FREE(response.extra_data.data);
238
239         return True;
240 }
241
242
243 /* List group SIDs a user SID is a member of */
244 static BOOL wbinfo_get_usersids(char *user_sid)
245 {
246         struct winbindd_request request;
247         struct winbindd_response response;
248         NSS_STATUS result;
249         int i;
250         const char *s;
251
252         ZERO_STRUCT(request);
253         ZERO_STRUCT(response);
254
255         /* Send request */
256         fstrcpy(request.data.sid, user_sid);
257
258         result = winbindd_request_response(WINBINDD_GETUSERSIDS, &request, &response);
259
260         if (result != NSS_STATUS_SUCCESS)
261                 return False;
262
263         s = (const char *)response.extra_data.data;
264         for (i = 0; i < response.data.num_entries; i++) {
265                 d_printf("%s\n", s);
266                 s += strlen(s) + 1;
267         }
268
269         SAFE_FREE(response.extra_data.data);
270
271         return True;
272 }
273
274 static BOOL wbinfo_get_userdomgroups(const char *user_sid)
275 {
276         struct winbindd_request request;
277         struct winbindd_response response;
278         NSS_STATUS result;
279
280         ZERO_STRUCT(request);
281         ZERO_STRUCT(response);
282
283         /* Send request */
284         fstrcpy(request.data.sid, user_sid);
285
286         result = winbindd_request_response(WINBINDD_GETUSERDOMGROUPS, &request,
287                                   &response);
288
289         if (result != NSS_STATUS_SUCCESS)
290                 return False;
291
292         if (response.data.num_entries != 0)
293                 printf("%s", (char *)response.extra_data.data);
294         
295         SAFE_FREE(response.extra_data.data);
296
297         return True;
298 }
299
300 /* Convert NetBIOS name to IP */
301
302 static BOOL wbinfo_wins_byname(char *name)
303 {
304         struct winbindd_request request;
305         struct winbindd_response response;
306
307         ZERO_STRUCT(request);
308         ZERO_STRUCT(response);
309
310         /* Send request */
311
312         fstrcpy(request.data.winsreq, name);
313
314         if (winbindd_request_response(WINBINDD_WINS_BYNAME, &request, &response) !=
315             NSS_STATUS_SUCCESS) {
316                 return False;
317         }
318
319         /* Display response */
320
321         d_printf("%s\n", response.data.winsresp);
322
323         return True;
324 }
325
326 /* Convert IP to NetBIOS name */
327
328 static BOOL wbinfo_wins_byip(char *ip)
329 {
330         struct winbindd_request request;
331         struct winbindd_response response;
332
333         ZERO_STRUCT(request);
334         ZERO_STRUCT(response);
335
336         /* Send request */
337
338         fstrcpy(request.data.winsreq, ip);
339
340         if (winbindd_request_response(WINBINDD_WINS_BYIP, &request, &response) !=
341             NSS_STATUS_SUCCESS) {
342                 return False;
343         }
344
345         /* Display response */
346
347         d_printf("%s\n", response.data.winsresp);
348
349         return True;
350 }
351
352 /* List trusted domains */
353
354 static BOOL wbinfo_list_domains(BOOL list_all_domains)
355 {
356         struct winbindd_request request;
357         struct winbindd_response response;
358
359         ZERO_STRUCT(request);
360         ZERO_STRUCT(response);
361
362         /* Send request */
363
364         request.data.list_all_domains = list_all_domains;
365
366         if (winbindd_request_response(WINBINDD_LIST_TRUSTDOM, &request, &response) !=
367             NSS_STATUS_SUCCESS)
368                 return False;
369
370         /* Display response */
371
372         if (response.extra_data.data) {
373                 const char *extra_data = (char *)response.extra_data.data;
374                 fstring name;
375                 char *p;
376
377                 while(next_token(&extra_data, name, "\n", sizeof(fstring))) {
378                         p = strchr(name, '\\');
379                         if (p == 0) {
380                                 d_fprintf(stderr, "Got invalid response: %s\n",
381                                          extra_data);
382                                 return False;
383                         }
384                         *p = 0;
385                         d_printf("%s\n", name);
386                 }
387
388                 SAFE_FREE(response.extra_data.data);
389         }
390
391         return True;
392 }
393
394 /* List own domain */
395
396 static BOOL wbinfo_list_own_domain(void)
397 {
398         d_printf("%s\n", get_winbind_domain());
399
400         return True;
401 }
402
403 /* show sequence numbers */
404 static BOOL wbinfo_show_sequence(const char *domain)
405 {
406         struct winbindd_request  request;
407         struct winbindd_response response;
408
409         ZERO_STRUCT(response);
410         ZERO_STRUCT(request);
411
412         if ( domain )
413                 fstrcpy( request.domain_name, domain );
414
415         /* Send request */
416
417         if (winbindd_request_response(WINBINDD_SHOW_SEQUENCE, &request, &response) !=
418             NSS_STATUS_SUCCESS)
419                 return False;
420
421         /* Display response */
422
423         if (response.extra_data.data) {
424                 char *extra_data = (char *)response.extra_data.data;
425                 d_printf("%s", extra_data);
426                 SAFE_FREE(response.extra_data.data);
427         }
428
429         return True;
430 }
431
432 /* Show domain info */
433
434 static BOOL wbinfo_domain_info(const char *domain_name)
435 {
436         struct winbindd_request request;
437         struct winbindd_response response;
438
439         ZERO_STRUCT(request);
440         ZERO_STRUCT(response);
441
442         if ((strequal(domain_name, ".")) || (domain_name[0] == '\0'))
443                 fstrcpy(request.domain_name, get_winbind_domain());
444         else
445                 fstrcpy(request.domain_name, domain_name);
446
447         /* Send request */
448
449         if (winbindd_request_response(WINBINDD_DOMAIN_INFO, &request, &response) !=
450             NSS_STATUS_SUCCESS)
451                 return False;
452
453         /* Display response */
454
455         d_printf("Name              : %s\n", response.data.domain_info.name);
456         d_printf("Alt_Name          : %s\n", response.data.domain_info.alt_name);
457
458         d_printf("SID               : %s\n", response.data.domain_info.sid);
459
460         d_printf("Active Directory  : %s\n",
461                  response.data.domain_info.active_directory ? "Yes" : "No");
462         d_printf("Native            : %s\n",
463                  response.data.domain_info.native_mode ? "Yes" : "No");
464
465         d_printf("Primary           : %s\n",
466                  response.data.domain_info.primary ? "Yes" : "No");
467
468         d_printf("Sequence          : %d\n", response.data.domain_info.sequence_number);
469
470         return True;
471 }
472
473 /* Get a foreign DC's name */
474 static BOOL wbinfo_getdcname(const char *domain_name)
475 {
476         struct winbindd_request request;
477         struct winbindd_response response;
478
479         ZERO_STRUCT(request);
480         ZERO_STRUCT(response);
481
482         fstrcpy(request.domain_name, domain_name);
483
484         /* Send request */
485
486         if (winbindd_request_response(WINBINDD_GETDCNAME, &request, &response) !=
487             NSS_STATUS_SUCCESS) {
488                 d_fprintf(stderr, "Could not get dc name for %s\n", domain_name);
489                 return False;
490         }
491
492         /* Display response */
493
494         d_printf("%s\n", response.data.dc_name);
495
496         return True;
497 }
498
499 /* Check trust account password */
500
501 static BOOL wbinfo_check_secret(void)
502 {
503         struct winbindd_response response;
504         NSS_STATUS result;
505
506         ZERO_STRUCT(response);
507
508         result = winbindd_request_response(WINBINDD_CHECK_MACHACC, NULL, &response);
509                 
510         d_printf("checking the trust secret via RPC calls %s\n", 
511                  (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed");
512
513         if (result != NSS_STATUS_SUCCESS)       
514                 d_fprintf(stderr, "error code was %s (0x%x)\n", 
515                          response.data.auth.nt_status_string, 
516                          response.data.auth.nt_status);
517         
518         return result == NSS_STATUS_SUCCESS;    
519 }
520
521 /* Convert uid to sid */
522
523 static BOOL wbinfo_uid_to_sid(uid_t uid)
524 {
525         struct winbindd_request request;
526         struct winbindd_response response;
527
528         ZERO_STRUCT(request);
529         ZERO_STRUCT(response);
530
531         /* Send request */
532
533         request.data.uid = uid;
534
535         if (winbindd_request_response(WINBINDD_UID_TO_SID, &request, &response) !=
536             NSS_STATUS_SUCCESS)
537                 return False;
538
539         /* Display response */
540
541         d_printf("%s\n", response.data.sid.sid);
542
543         return True;
544 }
545
546 /* Convert gid to sid */
547
548 static BOOL wbinfo_gid_to_sid(gid_t gid)
549 {
550         struct winbindd_request request;
551         struct winbindd_response response;
552
553         ZERO_STRUCT(request);
554         ZERO_STRUCT(response);
555
556         /* Send request */
557
558         request.data.gid = gid;
559
560         if (winbindd_request_response(WINBINDD_GID_TO_SID, &request, &response) !=
561             NSS_STATUS_SUCCESS)
562                 return False;
563
564         /* Display response */
565
566         d_printf("%s\n", response.data.sid.sid);
567
568         return True;
569 }
570
571 /* Convert sid to uid */
572
573 static BOOL wbinfo_sid_to_uid(char *sid)
574 {
575         struct winbindd_request request;
576         struct winbindd_response response;
577
578         ZERO_STRUCT(request);
579         ZERO_STRUCT(response);
580
581         /* Send request */
582
583         fstrcpy(request.data.sid, sid);
584
585         if (winbindd_request_response(WINBINDD_SID_TO_UID, &request, &response) !=
586             NSS_STATUS_SUCCESS)
587                 return False;
588
589         /* Display response */
590
591         d_printf("%d\n", (int)response.data.uid);
592
593         return True;
594 }
595
596 static BOOL wbinfo_sid_to_gid(char *sid)
597 {
598         struct winbindd_request request;
599         struct winbindd_response response;
600
601         ZERO_STRUCT(request);
602         ZERO_STRUCT(response);
603
604         /* Send request */
605
606         fstrcpy(request.data.sid, sid);
607
608         if (winbindd_request_response(WINBINDD_SID_TO_GID, &request, &response) !=
609             NSS_STATUS_SUCCESS)
610                 return False;
611
612         /* Display response */
613
614         d_printf("%d\n", (int)response.data.gid);
615
616         return True;
617 }
618
619 /* Convert sid to string */
620
621 static BOOL wbinfo_lookupsid(char *sid)
622 {
623         struct winbindd_request request;
624         struct winbindd_response response;
625
626         ZERO_STRUCT(request);
627         ZERO_STRUCT(response);
628
629         /* Send off request */
630
631         fstrcpy(request.data.sid, sid);
632
633         if (winbindd_request_response(WINBINDD_LOOKUPSID, &request, &response) !=
634             NSS_STATUS_SUCCESS)
635                 return False;
636
637         /* Display response */
638
639         d_printf("%s%c%s %d\n", response.data.name.dom_name, 
640                  winbind_separator(), response.data.name.name, 
641                  response.data.name.type);
642
643         return True;
644 }
645
646 static const char *sid_type_lookup(enum lsa_SidType r)
647 {
648         switch (r) {
649                 case SID_NAME_USE_NONE: return "SID_NAME_USE_NONE"; break;
650                 case SID_NAME_USER: return "SID_NAME_USER"; break;
651                 case SID_NAME_DOM_GRP: return "SID_NAME_DOM_GRP"; break;
652                 case SID_NAME_DOMAIN: return "SID_NAME_DOMAIN"; break;
653                 case SID_NAME_ALIAS: return "SID_NAME_ALIAS"; break;
654                 case SID_NAME_WKN_GRP: return "SID_NAME_WKN_GRP"; break;
655                 case SID_NAME_DELETED: return "SID_NAME_DELETED"; break;
656                 case SID_NAME_INVALID: return "SID_NAME_INVALID"; break;
657                 case SID_NAME_UNKNOWN: return "SID_NAME_UNKNOWN"; break;
658         }
659         return "Invalid sid type\n";
660 }
661
662 /* Convert string to sid */
663
664 static BOOL wbinfo_lookupname(char *name)
665 {
666         struct winbindd_request request;
667         struct winbindd_response response;
668
669         /* Send off request */
670
671         ZERO_STRUCT(request);
672         ZERO_STRUCT(response);
673
674         parse_wbinfo_domain_user(name, request.data.name.dom_name, 
675                                  request.data.name.name);
676
677         if (winbindd_request_response(WINBINDD_LOOKUPNAME, &request, &response) !=
678             NSS_STATUS_SUCCESS)
679                 return False;
680
681         /* Display response */
682
683         d_printf("%s %s (%d)\n", response.data.sid.sid, sid_type_lookup(response.data.sid.type), response.data.sid.type);
684
685         return True;
686 }
687
688 /* Authenticate a user with a plaintext password */
689
690 static BOOL wbinfo_auth_krb5(char *username, const char *cctype, uint32_t flags)
691 {
692         struct winbindd_request request;
693         struct winbindd_response response;
694         NSS_STATUS result;
695         char *p;
696
697         /* Send off request */
698
699         ZERO_STRUCT(request);
700         ZERO_STRUCT(response);
701
702         p = strchr(username, '%');
703
704         if (p) {
705                 *p = 0;
706                 fstrcpy(request.data.auth.user, username);
707                 fstrcpy(request.data.auth.pass, p + 1);
708                 *p = '%';
709         } else
710                 fstrcpy(request.data.auth.user, username);
711
712         request.flags = flags;
713
714         fstrcpy(request.data.auth.krb5_cc_type, cctype);
715
716         request.data.auth.uid = geteuid();
717
718         result = winbindd_request_response(WINBINDD_PAM_AUTH, &request, &response);
719
720         /* Display response */
721
722         d_printf("plaintext kerberos password authentication for [%s] %s (requesting cctype: %s)\n", 
723                 username, (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed", cctype);
724
725         if (response.data.auth.nt_status)
726                 d_fprintf(stderr, "error code was %s (0x%x)\nerror messsage was: %s\n", 
727                          response.data.auth.nt_status_string, 
728                          response.data.auth.nt_status,
729                          response.data.auth.error_string);
730
731         if (result == NSS_STATUS_SUCCESS) {
732
733                 if (request.flags & WBFLAG_PAM_INFO3_TEXT) {
734                         if (response.data.auth.info3.user_flgs & NETLOGON_CACHED_ACCOUNT) {
735                                 d_printf("user_flgs: NETLOGON_CACHED_ACCOUNT\n");
736                         }
737                 }
738
739                 if (response.data.auth.krb5ccname[0] != '\0') {
740                         d_printf("credentials were put in: %s\n", response.data.auth.krb5ccname);
741                 } else {
742                         d_printf("no credentials cached\n");
743                 }
744         }
745
746         return result == NSS_STATUS_SUCCESS;
747 }
748
749 /* Authenticate a user with a plaintext password */
750
751 static BOOL wbinfo_auth(char *username)
752 {
753         struct winbindd_request request;
754         struct winbindd_response response;
755         NSS_STATUS result;
756         char *p;
757
758         /* Send off request */
759
760         ZERO_STRUCT(request);
761         ZERO_STRUCT(response);
762
763         p = strchr(username, '%');
764
765         if (p) {
766                 *p = 0;
767                 fstrcpy(request.data.auth.user, username);
768                 fstrcpy(request.data.auth.pass, p + 1);
769                 *p = '%';
770         } else
771                 fstrcpy(request.data.auth.user, username);
772
773         result = winbindd_request_response(WINBINDD_PAM_AUTH, &request, &response);
774
775         /* Display response */
776
777         d_printf("plaintext password authentication %s\n", 
778                (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed");
779
780         if (response.data.auth.nt_status)
781                 d_fprintf(stderr, "error code was %s (0x%x)\nerror messsage was: %s\n", 
782                          response.data.auth.nt_status_string, 
783                          response.data.auth.nt_status,
784                          response.data.auth.error_string);
785
786         return result == NSS_STATUS_SUCCESS;
787 }
788
789 /* Authenticate a user with a challenge/response */
790
791 static BOOL wbinfo_auth_crap(char *username)
792 {
793         struct winbindd_request request;
794         struct winbindd_response response;
795         NSS_STATUS result;
796         fstring name_user;
797         fstring name_domain;
798         fstring pass;
799         char *p;
800
801         /* Send off request */
802
803         ZERO_STRUCT(request);
804         ZERO_STRUCT(response);
805
806         p = strchr(username, '%');
807
808         if (p) {
809                 *p = 0;
810                 fstrcpy(pass, p + 1);
811         }
812                 
813         parse_wbinfo_domain_user(username, name_domain, name_user);
814
815         request.data.auth_crap.logon_parameters = MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT | MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT;
816
817         fstrcpy(request.data.auth_crap.user, name_user);
818
819         fstrcpy(request.data.auth_crap.domain, 
820                               name_domain);
821
822         generate_random_buffer(request.data.auth_crap.chal, 8);
823         
824         if (lp_client_ntlmv2_auth()) {
825                 DATA_BLOB server_chal;
826                 DATA_BLOB names_blob;   
827
828                 DATA_BLOB lm_response;
829                 DATA_BLOB nt_response;
830
831                 TALLOC_CTX *mem_ctx;
832                 mem_ctx = talloc_new(NULL);
833                 if (mem_ctx == NULL) {
834                         d_printf("talloc_new failed\n");
835                         return False;
836                 }
837
838                 server_chal = data_blob(request.data.auth_crap.chal, 8); 
839                 
840                 /* Pretend this is a login to 'us', for blob purposes */
841                 names_blob = NTLMv2_generate_names_blob(mem_ctx, lp_netbios_name(), lp_workgroup());
842                 
843                 if (!SMBNTLMv2encrypt(mem_ctx, name_user, name_domain, pass, &server_chal, 
844                                       &names_blob,
845                                       &lm_response, &nt_response, NULL, NULL)) {
846                         data_blob_free(&names_blob);
847                         data_blob_free(&server_chal);
848                         return False;
849                 }
850                 data_blob_free(&names_blob);
851                 data_blob_free(&server_chal);
852
853                 memcpy(request.data.auth_crap.nt_resp, nt_response.data, 
854                        MIN(nt_response.length, 
855                            sizeof(request.data.auth_crap.nt_resp)));
856                 request.data.auth_crap.nt_resp_len = nt_response.length;
857
858                 memcpy(request.data.auth_crap.lm_resp, lm_response.data, 
859                        MIN(lm_response.length, 
860                            sizeof(request.data.auth_crap.lm_resp)));
861                 request.data.auth_crap.lm_resp_len = lm_response.length;
862                        
863                 data_blob_free(&nt_response);
864                 data_blob_free(&lm_response);
865
866         } else {
867                 if (lp_client_lanman_auth() 
868                     && SMBencrypt(pass, request.data.auth_crap.chal, 
869                                (unsigned char *)request.data.auth_crap.lm_resp)) {
870                         request.data.auth_crap.lm_resp_len = 24;
871                 } else {
872                         request.data.auth_crap.lm_resp_len = 0;
873                 }
874                 SMBNTencrypt(pass, request.data.auth_crap.chal,
875                              (unsigned char *)request.data.auth_crap.nt_resp);
876
877                 request.data.auth_crap.nt_resp_len = 24;
878         }
879
880         result = winbindd_request_response(WINBINDD_PAM_AUTH_CRAP, &request, &response);
881
882         /* Display response */
883
884         d_printf("challenge/response password authentication %s\n", 
885                (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed");
886
887         if (response.data.auth.nt_status)
888                 d_fprintf(stderr, "error code was %s (0x%x)\nerror messsage was: %s\n", 
889                          response.data.auth.nt_status_string, 
890                          response.data.auth.nt_status,
891                          response.data.auth.error_string);
892
893         return result == NSS_STATUS_SUCCESS;
894 }
895
896 /* Print domain users */
897
898 static BOOL print_domain_users(const char *domain)
899 {
900         struct winbindd_request request;
901         struct winbindd_response response;
902         const char *extra_data;
903         fstring name;
904
905         /* Send request to winbind daemon */
906
907         ZERO_STRUCT(request);
908         ZERO_STRUCT(response);
909         
910         if (domain) {
911                 /* '.' is the special sign for our own domain */
912                 if ( strequal(domain, ".") )
913                         fstrcpy( request.domain_name, get_winbind_domain() );
914                 else
915                         fstrcpy( request.domain_name, domain );
916         }
917
918         if (winbindd_request_response(WINBINDD_LIST_USERS, &request, &response) !=
919             NSS_STATUS_SUCCESS)
920                 return False;
921
922         /* Look through extra data */
923
924         if (!response.extra_data.data)
925                 return False;
926
927         extra_data = (const char *)response.extra_data.data;
928
929         while(next_token(&extra_data, name, ",", sizeof(fstring)))
930                 d_printf("%s\n", name);
931         
932         SAFE_FREE(response.extra_data.data);
933
934         return True;
935 }
936
937 /* Print domain groups */
938
939 static BOOL print_domain_groups(const char *domain)
940 {
941         struct winbindd_request  request;
942         struct winbindd_response response;
943         const char *extra_data;
944         fstring name;
945
946         ZERO_STRUCT(request);
947         ZERO_STRUCT(response);
948
949         if (domain) {
950                 if ( strequal(domain, ".") )
951                         fstrcpy( request.domain_name, get_winbind_domain() );
952                 else
953                         fstrcpy( request.domain_name, domain );
954         }
955
956         if (winbindd_request_response(WINBINDD_LIST_GROUPS, &request, &response) !=
957             NSS_STATUS_SUCCESS)
958                 return False;
959
960         /* Look through extra data */
961
962         if (!response.extra_data.data)
963                 return False;
964
965         extra_data = (const char *)response.extra_data.data;
966
967         while(next_token(&extra_data, name, ",", sizeof(fstring)))
968                 d_printf("%s\n", name);
969
970         SAFE_FREE(response.extra_data.data);
971         
972         return True;
973 }
974
975 static BOOL wbinfo_ping(void)
976 {
977         NSS_STATUS result;
978
979         result = winbindd_request_response(WINBINDD_PING, NULL, NULL);
980
981         /* Display response */
982
983         d_printf("Ping to winbindd %s on fd %d\n", 
984                (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed", winbindd_fd);
985
986         return result == NSS_STATUS_SUCCESS;
987 }
988
989 /* Main program */
990
991 enum {
992         OPT_SET_AUTH_USER = 1000,
993         OPT_GET_AUTH_USER,
994         OPT_DOMAIN_NAME,
995         OPT_SEQUENCE,
996         OPT_GETDCNAME,
997         OPT_USERDOMGROUPS,
998         OPT_USERSIDS,
999         OPT_ALLOCATE_UID,
1000         OPT_ALLOCATE_GID,
1001         OPT_SEPARATOR,
1002         OPT_LIST_ALL_DOMAINS,
1003         OPT_LIST_OWN_DOMAIN,
1004         OPT_UID_INFO,
1005         OPT_GROUP_INFO,
1006 };
1007
1008 int main(int argc, char **argv, char **envp)
1009 {
1010         int opt;
1011
1012         poptContext pc;
1013         static char *string_arg;
1014         static char *opt_domain_name;
1015         static int int_arg;
1016         int result = 1;
1017
1018         struct poptOption long_options[] = {
1019                 POPT_AUTOHELP
1020
1021                 /* longName, shortName, argInfo, argPtr, value, descrip, 
1022                    argDesc */
1023
1024                 { "domain-users", 'u', POPT_ARG_NONE, 0, 'u', "Lists all domain users", "domain"},
1025                 { "domain-groups", 'g', POPT_ARG_NONE, 0, 'g', "Lists all domain groups", "domain" },
1026                 { "WINS-by-name", 'N', POPT_ARG_STRING, &string_arg, 'N', "Converts NetBIOS name to IP", "NETBIOS-NAME" },
1027                 { "WINS-by-ip", 'I', POPT_ARG_STRING, &string_arg, 'I', "Converts IP address to NetBIOS name", "IP" },
1028                 { "name-to-sid", 'n', POPT_ARG_STRING, &string_arg, 'n', "Converts name to sid", "NAME" },
1029                 { "sid-to-name", 's', POPT_ARG_STRING, &string_arg, 's', "Converts sid to name", "SID" },
1030                 { "uid-to-sid", 'U', POPT_ARG_INT, &int_arg, 'U', "Converts uid to sid" , "UID" },
1031                 { "gid-to-sid", 'G', POPT_ARG_INT, &int_arg, 'G', "Converts gid to sid", "GID" },
1032                 { "sid-to-uid", 'S', POPT_ARG_STRING, &string_arg, 'S', "Converts sid to uid", "SID" },
1033                 { "sid-to-gid", 'Y', POPT_ARG_STRING, &string_arg, 'Y', "Converts sid to gid", "SID" },
1034                 { "check-secret", 't', POPT_ARG_NONE, 0, 't', "Check shared secret" },
1035                 { "trusted-domains", 'm', POPT_ARG_NONE, 0, 'm', "List trusted domains" },
1036                 { "all-domains", 0, POPT_ARG_NONE, 0, OPT_LIST_ALL_DOMAINS, "List all domains (trusted and own domain)" },
1037                 { "own-domain", 0, POPT_ARG_NONE, 0, OPT_LIST_OWN_DOMAIN, "List own domain" },
1038                 { "sequence", 0, POPT_ARG_NONE, 0, OPT_SEQUENCE, "Show sequence numbers of all domains" },
1039                 { "domain-info", 'D', POPT_ARG_STRING, &string_arg, 'D', "Show most of the info we have about the domain" },
1040                 { "user-info", 'i', POPT_ARG_STRING, &string_arg, 'i', "Get user info", "USER" },
1041                 { "uid-info", 0, POPT_ARG_INT, &int_arg, OPT_UID_INFO, "Get user info from uid", "UID" },
1042                 { "group-info", 0, POPT_ARG_STRING, &string_arg, OPT_GROUP_INFO, "Get group info", "GROUP" },
1043                 { "user-groups", 'r', POPT_ARG_STRING, &string_arg, 'r', "Get user groups", "USER" },
1044                 { "user-domgroups", 0, POPT_ARG_STRING, &string_arg,
1045                   OPT_USERDOMGROUPS, "Get user domain groups", "SID" },
1046                 { "user-sids", 0, POPT_ARG_STRING, &string_arg, OPT_USERSIDS, "Get user group sids for user SID", "SID" },
1047                 { "authenticate", 'a', POPT_ARG_STRING, &string_arg, 'a', "authenticate user", "user%password" },
1048                 { "getdcname", 0, POPT_ARG_STRING, &string_arg, OPT_GETDCNAME,
1049                   "Get a DC name for a foreign domain", "domainname" },
1050                 { "ping", 'p', POPT_ARG_NONE, 0, 'p', "Ping winbindd to see if it is alive" },
1051                 { "domain", 0, POPT_ARG_STRING, &opt_domain_name, OPT_DOMAIN_NAME, "Define to the domain to restrict operation", "domain" },
1052 #ifdef HAVE_KRB5
1053                 { "krb5auth", 'K', POPT_ARG_STRING, &string_arg, 'K', "authenticate user using Kerberos", "user%password" },
1054                         /* destroys wbinfo --help output */
1055                         /* "user%password,DOM\\user%password,user@EXAMPLE.COM,EXAMPLE.COM\\user%password" }, */
1056 #endif
1057                 { "separator", 0, POPT_ARG_NONE, 0, OPT_SEPARATOR, "Get the active winbind separator", NULL },
1058                 POPT_COMMON_VERSION
1059                 POPT_COMMON_SAMBA
1060                 POPT_TABLEEND
1061         };
1062
1063         /* Parse options */
1064
1065         pc = poptGetContext("wbinfo", argc, (const char **)argv, long_options, 0);
1066
1067         /* Parse command line options */
1068
1069         if (argc == 1) {
1070                 poptPrintHelp(pc, stderr, 0);
1071                 return 1;
1072         }
1073
1074         while((opt = poptGetNextOpt(pc)) != -1) {
1075                 /* get the generic configuration parameters like --domain */
1076         }
1077
1078         poptFreeContext(pc);
1079
1080         pc = poptGetContext(NULL, argc, (const char **)argv, long_options, 
1081                             POPT_CONTEXT_KEEP_FIRST);
1082
1083         while((opt = poptGetNextOpt(pc)) != -1) {
1084                 switch (opt) {
1085                 case 'u':
1086                         if (!print_domain_users(opt_domain_name)) {
1087                                 d_fprintf(stderr, "Error looking up domain users\n");
1088                                 goto done;
1089                         }
1090                         break;
1091                 case 'g':
1092                         if (!print_domain_groups(opt_domain_name)) {
1093                                 d_fprintf(stderr, "Error looking up domain groups\n");
1094                                 goto done;
1095                         }
1096                         break;
1097                 case 's':
1098                         if (!wbinfo_lookupsid(string_arg)) {
1099                                 d_fprintf(stderr, "Could not lookup sid %s\n", string_arg);
1100                                 goto done;
1101                         }
1102                         break;
1103                 case 'n':
1104                         if (!wbinfo_lookupname(string_arg)) {
1105                                 d_fprintf(stderr, "Could not lookup name %s\n", string_arg);
1106                                 goto done;
1107                         }
1108                         break;
1109                 case 'N':
1110                         if (!wbinfo_wins_byname(string_arg)) {
1111                                 d_fprintf(stderr, "Could not lookup WINS by name %s\n", string_arg);
1112                                 goto done;
1113                         }
1114                         break;
1115                 case 'I':
1116                         if (!wbinfo_wins_byip(string_arg)) {
1117                                 d_fprintf(stderr, "Could not lookup WINS by IP %s\n", string_arg);
1118                                 goto done;
1119                         }
1120                         break;
1121                 case 'U':
1122                         if (!wbinfo_uid_to_sid(int_arg)) {
1123                                 d_fprintf(stderr, "Could not convert uid %d to sid\n", int_arg);
1124                                 goto done;
1125                         }
1126                         break;
1127                 case 'G':
1128                         if (!wbinfo_gid_to_sid(int_arg)) {
1129                                 d_fprintf(stderr, "Could not convert gid %d to sid\n",
1130                                        int_arg);
1131                                 goto done;
1132                         }
1133                         break;
1134                 case 'S':
1135                         if (!wbinfo_sid_to_uid(string_arg)) {
1136                                 d_fprintf(stderr, "Could not convert sid %s to uid\n",
1137                                        string_arg);
1138                                 goto done;
1139                         }
1140                         break;
1141                 case 'Y':
1142                         if (!wbinfo_sid_to_gid(string_arg)) {
1143                                 d_fprintf(stderr, "Could not convert sid %s to gid\n",
1144                                        string_arg);
1145                                 goto done;
1146                         }
1147                         break;
1148                 case 't':
1149                         if (!wbinfo_check_secret()) {
1150                                 d_fprintf(stderr, "Could not check secret\n");
1151                                 goto done;
1152                         }
1153                         break;
1154                 case 'm':
1155                         if (!wbinfo_list_domains(False)) {
1156                                 d_fprintf(stderr, "Could not list trusted domains\n");
1157                                 goto done;
1158                         }
1159                         break;
1160                 case OPT_SEQUENCE:
1161                         if (!wbinfo_show_sequence(opt_domain_name)) {
1162                                 d_fprintf(stderr, "Could not show sequence numbers\n");
1163                                 goto done;
1164                         }
1165                         break;
1166                 case 'D':
1167                         if (!wbinfo_domain_info(string_arg)) {
1168                                 d_fprintf(stderr, "Could not get domain info\n");
1169                                 goto done;
1170                         }
1171                         break;
1172                 case 'i':
1173                         if (!wbinfo_get_userinfo(string_arg)) {
1174                                 d_fprintf(stderr, "Could not get info for user %s\n",
1175                                                   string_arg);
1176                                 goto done;
1177                         }
1178                         break;
1179                 case OPT_UID_INFO:
1180                         if ( !wbinfo_get_uidinfo(int_arg)) {
1181                                 d_fprintf(stderr, "Could not get info for uid "
1182                                                 "%d\n", int_arg);
1183                                 goto done;
1184                         }
1185                         break;
1186                 case OPT_GROUP_INFO:
1187                         if ( !wbinfo_get_groupinfo(string_arg)) {
1188                                 d_fprintf(stderr, "Could not get info for "
1189                                           "group %s\n", string_arg);
1190                                 goto done;
1191                         }
1192                         break;
1193                 case 'r':
1194                         if (!wbinfo_get_usergroups(string_arg)) {
1195                                 d_fprintf(stderr, "Could not get groups for user %s\n", 
1196                                        string_arg);
1197                                 goto done;
1198                         }
1199                         break;
1200                 case OPT_USERSIDS:
1201                         if (!wbinfo_get_usersids(string_arg)) {
1202                                 d_fprintf(stderr, "Could not get group SIDs for user SID %s\n", 
1203                                        string_arg);
1204                                 goto done;
1205                         }
1206                         break;
1207                 case OPT_USERDOMGROUPS:
1208                         if (!wbinfo_get_userdomgroups(string_arg)) {
1209                                 d_fprintf(stderr, "Could not get user's domain groups "
1210                                          "for user SID %s\n", string_arg);
1211                                 goto done;
1212                         }
1213                         break;
1214                 case 'a': {
1215                                 BOOL got_error = False;
1216
1217                                 if (!wbinfo_auth(string_arg)) {
1218                                         d_fprintf(stderr, "Could not authenticate user %s with "
1219                                                 "plaintext password\n", string_arg);
1220                                         got_error = True;
1221                                 }
1222
1223                                 if (!wbinfo_auth_crap(string_arg)) {
1224                                         d_fprintf(stderr, "Could not authenticate user %s with "
1225                                                 "challenge/response\n", string_arg);
1226                                         got_error = True;
1227                                 }
1228
1229                                 if (got_error)
1230                                         goto done;
1231                                 break;
1232                         }
1233                 case 'K': {
1234                                 uint32_t flags =  WBFLAG_PAM_KRB5 |
1235                                                 WBFLAG_PAM_CACHED_LOGIN |
1236                                                 WBFLAG_PAM_FALLBACK_AFTER_KRB5 |
1237                                                 WBFLAG_PAM_INFO3_TEXT;
1238
1239                                 if (!wbinfo_auth_krb5(string_arg, "FILE", flags)) {
1240                                         d_fprintf(stderr, "Could not authenticate user [%s] with "
1241                                                 "Kerberos (ccache: %s)\n", string_arg, "FILE");
1242                                         goto done;
1243                                 }
1244                                 break;
1245                         }
1246                 case 'p':
1247                         if (!wbinfo_ping()) {
1248                                 d_fprintf(stderr, "could not ping winbindd!\n");
1249                                 goto done;
1250                         }
1251                         break;
1252                 case OPT_GETDCNAME:
1253                         if (!wbinfo_getdcname(string_arg)) {
1254                                 goto done;
1255                         }
1256                         break;
1257                 case OPT_SEPARATOR: {
1258                         const char sep = winbind_separator_int(True);
1259                         if ( !sep ) {
1260                                 goto done;
1261                         }
1262                         d_printf("%c\n", sep);
1263                         break;
1264                 }
1265                 case OPT_LIST_ALL_DOMAINS:
1266                         if (!wbinfo_list_domains(True)) {
1267                                 goto done;
1268                         }
1269                         break;
1270                 case OPT_LIST_OWN_DOMAIN:
1271                         if (!wbinfo_list_own_domain()) {
1272                                 goto done;
1273                         }
1274                         break;
1275                 /* generic configuration options */
1276                 case OPT_DOMAIN_NAME:
1277                         break;
1278                 default:
1279                         d_fprintf(stderr, "Invalid option\n");
1280                         poptPrintHelp(pc, stderr, 0);
1281                         goto done;
1282                 }
1283         }
1284
1285         result = 0;
1286
1287         /* Exit code */
1288
1289  done:
1290         poptFreeContext(pc);
1291         return result;
1292 }