This patch makes the 'winbind use default domain' code interact better with
[ira/wip.git] / source3 / nsswitch / wbinfo.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 2.0
4
5    Winbind status program.
6
7    Copyright (C) Tim Potter      2000
8    Copyright (C) Andrew Bartlett 2002
9    
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include "includes.h"
26 #include "winbindd.h"
27 #include "debug.h"
28
29 /* Prototypes from common.h */
30
31 NSS_STATUS winbindd_request(int req_type, 
32                             struct winbindd_request *request,
33                             struct winbindd_response *response);
34
35 static char get_winbind_separator(void)
36 {
37         struct winbindd_response response;
38         char winbind_separator;
39
40         ZERO_STRUCT(response);
41
42         /* Send off request */
43
44         if (winbindd_request(WINBINDD_INFO, NULL, &response) !=
45             NSS_STATUS_SUCCESS) {
46                 printf("could not obtain winbind seperator!\n");
47                 exit(1);
48         }
49
50         winbind_separator = response.data.info.winbind_separator;
51
52         if (!winbind_separator) {
53                 printf("winbind separator was NULL!\n");
54                 exit(1);
55         }
56         
57         return winbind_separator;
58
59 }
60
61 /* Copy of parse_domain_user from winbindd_util.c.  Parse a string of the
62    form DOMAIN/user into a domain and a user */
63
64 static BOOL parse_wbinfo_domain_user(const char *domuser, fstring domain, fstring user)
65 {
66
67         char *p = strchr(domuser,get_winbind_separator());
68
69         if (!p) {
70                 fstrcpy(user, domuser);
71                 domain[0]=0;
72                 return True;
73         }
74         
75         fstrcpy(user, p+1);
76         fstrcpy(domain, domuser);
77         domain[PTR_DIFF(p, domuser)] = 0;
78         strupper(domain);
79         return True;
80 }
81
82 /* List groups a user is a member of */
83
84 static BOOL wbinfo_get_usergroups(char *user)
85 {
86         struct winbindd_request request;
87         struct winbindd_response response;
88         NSS_STATUS result;
89         int i;
90         
91         ZERO_STRUCT(response);
92
93         /* Send request */
94
95         fstrcpy(request.data.username, user);
96
97         result = winbindd_request(WINBINDD_GETGROUPS, &request, &response);
98
99         if (result != NSS_STATUS_SUCCESS)
100                 return False;
101
102         for (i = 0; i < response.data.num_entries; i++)
103                 printf("%d\n", (int)((gid_t *)response.extra_data)[i]);
104
105         SAFE_FREE(response.extra_data);
106
107         return True;
108 }
109
110 /* List trusted domains */
111
112 static BOOL wbinfo_list_domains(void)
113 {
114         struct winbindd_response response;
115         fstring name;
116
117         ZERO_STRUCT(response);
118
119         /* Send request */
120
121         if (winbindd_request(WINBINDD_LIST_TRUSTDOM, NULL, &response) !=
122             NSS_STATUS_SUCCESS) {
123                 return False;
124         }
125
126         /* Display response */
127
128         if (response.extra_data) {
129                 char *extra_data = (char *)response.extra_data;
130
131                 while(next_token(&extra_data, name, ",", sizeof(fstring)))
132                         printf("%s\n", name);
133
134                 SAFE_FREE(response.extra_data);
135         }
136
137         return True;
138 }
139
140 /* Check trust account password */
141
142 static BOOL wbinfo_check_secret(void)
143 {
144         struct winbindd_response response;
145         BOOL result;
146
147         ZERO_STRUCT(response);
148
149         result = winbindd_request(WINBINDD_CHECK_MACHACC, NULL, &response) ==
150                 NSS_STATUS_SUCCESS;
151
152         if (result) {
153
154                 if (response.data.num_entries == 0) {
155                         printf("Secret is good\n");
156                 } else {
157                         printf("Secret is bad\n0x%08x\n", 
158                                response.data.num_entries);
159                 }
160
161                 return True;
162         }
163
164         return False;
165 }
166
167 /* Convert uid to sid */
168
169 static BOOL wbinfo_uid_to_sid(uid_t uid)
170 {
171         struct winbindd_request request;
172         struct winbindd_response response;
173
174         ZERO_STRUCT(request);
175         ZERO_STRUCT(response);
176
177         /* Send request */
178
179         request.data.uid = uid;
180         if (winbindd_request(WINBINDD_UID_TO_SID, &request, &response) !=
181             NSS_STATUS_SUCCESS) {
182                 return False;
183         }
184
185         /* Display response */
186
187         printf("%s\n", response.data.sid.sid);
188
189         return True;
190 }
191
192 /* Convert gid to sid */
193
194 static BOOL wbinfo_gid_to_sid(gid_t gid)
195 {
196         struct winbindd_request request;
197         struct winbindd_response response;
198
199         ZERO_STRUCT(request);
200         ZERO_STRUCT(response);
201
202         /* Send request */
203
204         request.data.gid = gid;
205         if (winbindd_request(WINBINDD_GID_TO_SID, &request, &response) !=
206             NSS_STATUS_SUCCESS) {
207                 return False;
208         }
209
210         /* Display response */
211
212         printf("%s\n", response.data.sid.sid);
213
214         return True;
215 }
216
217 /* Convert sid to uid */
218
219 static BOOL wbinfo_sid_to_uid(char *sid)
220 {
221         struct winbindd_request request;
222         struct winbindd_response response;
223
224         ZERO_STRUCT(request);
225         ZERO_STRUCT(response);
226
227         /* Send request */
228
229         fstrcpy(request.data.sid, sid);
230         if (winbindd_request(WINBINDD_SID_TO_UID, &request, &response) !=
231             NSS_STATUS_SUCCESS) {
232                 return False;
233         }
234
235         /* Display response */
236
237         printf("%d\n", (int)response.data.uid);
238
239         return True;
240 }
241
242 static BOOL wbinfo_sid_to_gid(char *sid)
243 {
244         struct winbindd_request request;
245         struct winbindd_response response;
246
247         ZERO_STRUCT(request);
248         ZERO_STRUCT(response);
249
250         /* Send request */
251
252         fstrcpy(request.data.sid, sid);
253         if (winbindd_request(WINBINDD_SID_TO_GID, &request, &response) !=
254             NSS_STATUS_SUCCESS) {
255                 return False;
256         }
257
258         /* Display response */
259
260         printf("%d\n", (int)response.data.gid);
261
262         return True;
263 }
264
265 /* Convert sid to string */
266
267 static BOOL wbinfo_lookupsid(char *sid)
268 {
269         struct winbindd_request request;
270         struct winbindd_response response;
271
272         ZERO_STRUCT(request);
273         ZERO_STRUCT(response);
274
275         /* Send off request */
276
277         fstrcpy(request.data.sid, sid);
278         if (winbindd_request(WINBINDD_LOOKUPSID, &request, &response) !=
279             NSS_STATUS_SUCCESS) {
280                 return False;
281         }
282
283         /* Display response */
284
285         printf("%s %d\n", response.data.name.name, response.data.name.type);
286
287         return True;
288 }
289
290 /* Convert string to sid */
291
292 static BOOL wbinfo_lookupname(char *name)
293 {
294         struct winbindd_request request;
295         struct winbindd_response response;
296
297         /* Send off request */
298
299         ZERO_STRUCT(request);
300         ZERO_STRUCT(response);
301
302         fstrcpy(request.data.name, name);
303         if (winbindd_request(WINBINDD_LOOKUPNAME, &request, &response) !=
304             NSS_STATUS_SUCCESS) {
305                 return False;
306         }
307
308         /* Display response */
309
310         printf("%s %d\n", response.data.sid.sid, response.data.sid.type);
311
312         return True;
313 }
314
315 /* Authenticate a user with a plaintext password */
316
317 static BOOL wbinfo_auth(char *username)
318 {
319         struct winbindd_request request;
320         struct winbindd_response response;
321         NSS_STATUS result;
322         char *p;
323
324         /* Send off request */
325
326         ZERO_STRUCT(request);
327         ZERO_STRUCT(response);
328
329         p = strchr(username, '%');
330
331         if (p) {
332                 *p = 0;
333                 fstrcpy(request.data.auth.user, username);
334                 fstrcpy(request.data.auth.pass, p + 1);
335                 *p = '%';
336         } else
337                 fstrcpy(request.data.auth.user, username);
338
339         result = winbindd_request(WINBINDD_PAM_AUTH, &request, &response);
340
341         /* Display response */
342
343         printf("plaintext password authentication %s\n", 
344                (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed");
345
346         return result == NSS_STATUS_SUCCESS;
347 }
348
349 /* Authenticate a user with a challenge/response */
350
351 static BOOL wbinfo_auth_crap(char *username)
352 {
353         struct winbindd_request request;
354         struct winbindd_response response;
355         NSS_STATUS result;
356         fstring name_user;
357         fstring name_domain;
358         fstring pass;
359         char *p;
360
361         /* Send off request */
362
363         ZERO_STRUCT(request);
364         ZERO_STRUCT(response);
365
366         p = strchr(username, '%');
367
368         if (p) {
369                 *p = 0;
370                 fstrcpy(pass, p + 1);
371         }
372                 
373         parse_wbinfo_domain_user(username, name_domain, name_user);
374
375         fstrcpy(request.data.auth_crap.user, name_user);
376
377         fstrcpy(request.data.auth_crap.domain, name_domain);
378
379         generate_random_buffer(request.data.auth_crap.chal, 8, False);
380         
381         SMBencrypt((uchar *)pass, request.data.auth_crap.chal, 
382                    (uchar *)request.data.auth_crap.lm_resp);
383         SMBNTencrypt((uchar *)pass, request.data.auth_crap.chal,
384                      (uchar *)request.data.auth_crap.nt_resp);
385
386         request.data.auth_crap.lm_resp_len = 24;
387         request.data.auth_crap.nt_resp_len = 24;
388
389         result = winbindd_request(WINBINDD_PAM_AUTH_CRAP, &request, &response);
390
391         /* Display response */
392
393         printf("challenge/response password authentication %s\n", 
394                (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed");
395
396         return result == NSS_STATUS_SUCCESS;
397 }
398
399 /* Print domain users */
400
401 static BOOL print_domain_users(void)
402 {
403         struct winbindd_response response;
404         char *extra_data;
405         fstring name;
406
407         /* Send request to winbind daemon */
408
409         ZERO_STRUCT(response);
410
411         if (winbindd_request(WINBINDD_LIST_USERS, NULL, &response) !=
412             NSS_STATUS_SUCCESS) {
413                 return False;
414         }
415
416         /* Look through extra data */
417
418         if (!response.extra_data)
419                 return False;
420
421         extra_data = (char *)response.extra_data;
422
423         while(next_token(&extra_data, name, ",", sizeof(fstring)))
424                 printf("%s\n", name);
425         
426         SAFE_FREE(response.extra_data);
427
428         return True;
429 }
430
431 /* Print domain groups */
432
433 static BOOL print_domain_groups(void)
434 {
435         struct winbindd_response response;
436         char *extra_data;
437         fstring name;
438
439         ZERO_STRUCT(response);
440
441         if (winbindd_request(WINBINDD_LIST_GROUPS, NULL, &response) !=
442             NSS_STATUS_SUCCESS) {
443                 return False;
444         }
445
446         /* Look through extra data */
447
448         if (!response.extra_data)
449                 return False;
450
451         extra_data = (char *)response.extra_data;
452
453         while(next_token(&extra_data, name, ",", sizeof(fstring)))
454                 printf("%s\n", name);
455
456         SAFE_FREE(response.extra_data);
457         
458         return True;
459 }
460
461 /* Set the authorised user for winbindd access in secrets.tdb */
462
463 static BOOL wbinfo_set_auth_user(char *username)
464 {
465         char *password;
466
467         /* Separate into user and password */
468
469         password = strchr(username, '%');
470
471         if (password) {
472                 *password = 0;
473                 password++;
474         } else
475                 password = "";
476
477         /* Store in secrets.tdb */
478
479         if (!secrets_store(SECRETS_AUTH_USER, username, strlen(username) + 1) ||
480             !secrets_store(SECRETS_AUTH_PASSWORD, password, strlen(password) + 1)) {
481                 fprintf(stderr, "error storing authenticated user info\n");
482                 return False;
483         }
484
485         return True;
486 }
487
488 static BOOL wbinfo_ping(void)
489 {
490         NSS_STATUS result;
491         
492         result = winbindd_request(WINBINDD_PING, NULL, NULL);
493
494         /* Display response */
495
496         printf("'ping' to winbindd %s\n", 
497                (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed");
498
499         return result == NSS_STATUS_SUCCESS;
500 }
501
502 /* Print program usage */
503
504 static void usage(void)
505 {
506         printf("Usage: wbinfo -ug | -n name | -sSY sid | -UG uid/gid | -tm "
507                "| -a user%%password\n");
508         printf("\t-u\t\t\tlists all domain users\n");
509         printf("\t-g\t\t\tlists all domain groups\n");
510         printf("\t-n name\t\t\tconverts name to sid\n");
511         printf("\t-s sid\t\t\tconverts sid to name\n");
512         printf("\t-U uid\t\t\tconverts uid to sid\n");
513         printf("\t-G gid\t\t\tconverts gid to sid\n");
514         printf("\t-S sid\t\t\tconverts sid to uid\n");
515         printf("\t-Y sid\t\t\tconverts sid to gid\n");
516         printf("\t-t\t\t\tcheck shared secret\n");
517         printf("\t-m\t\t\tlist trusted domains\n");
518         printf("\t-r user\t\t\tget user groups\n");
519         printf("\t-a user%%password\tauthenticate user\n");
520         printf("\t-p 'ping' winbindd to see if it is alive\n");
521 }
522
523 /* Main program */
524
525 enum {
526         OPT_SET_AUTH_USER = 1000
527 };
528
529 int main(int argc, char **argv)
530 {
531         extern pstring global_myname;
532         int opt;
533
534         poptContext pc;
535         static char *string_arg;
536         static int int_arg;
537         BOOL got_command = False;
538
539         struct poptOption long_options[] = {
540
541                 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
542                 { "help", 'h', POPT_ARG_NONE, 0, 'h' },
543                 { "domain-users", 'u', POPT_ARG_NONE, 0, 'u' },
544                 { "domain-groups", 'g', POPT_ARG_NONE, 0, 'g' },
545                 { "name-to-sid", 'n', POPT_ARG_STRING, &string_arg, 'n' },
546                 { "sid-to-name", 's', POPT_ARG_STRING, &string_arg, 's' },
547                 { "uid-to-sid", 'U', POPT_ARG_INT, &int_arg, 'U' },
548                 { "gid-to-sid", 'G', POPT_ARG_INT, &int_arg, 'G' },
549                 { "sid-to-uid", 'S', POPT_ARG_STRING, &string_arg, 'S' },
550                 { "sid-to-gid", 'Y', POPT_ARG_STRING, &string_arg, 'Y' },
551                 { "check-secret", 't', POPT_ARG_NONE, 0, 't' },
552                 { "trusted-domains", 'm', POPT_ARG_NONE, 0, 'm' },
553                 { "user-groups", 'r', POPT_ARG_STRING, &string_arg, 'r' },
554                 { "authenticate", 'a', POPT_ARG_STRING, &string_arg, 'a' },
555                 { "set-auth-user", 0, POPT_ARG_STRING, &string_arg, OPT_SET_AUTH_USER },
556                 { "ping", 'p', POPT_ARG_NONE, 0, 'p' },
557                 { 0, 0, 0, 0 }
558         };
559
560         /* Samba client initialisation */
561
562         if (!*global_myname) {
563                 char *p;
564
565                 fstrcpy(global_myname, myhostname());
566                 p = strchr(global_myname, '.');
567                 if (p) {
568                         *p = 0;
569                 }
570         }
571
572         if (!lp_load(dyn_CONFIGFILE, True, False, False)) {
573                 fprintf(stderr, "wbinfo: error opening config file %s. Error was %s\n",
574                         dyn_CONFIGFILE, strerror(errno));
575                 exit(1);
576         }
577
578         load_interfaces();
579
580         /* Parse command line options */
581
582         if (argc == 1) {
583                 usage();
584                 return 1;
585         }
586
587         /* Parse options */
588
589         pc = poptGetContext("wbinfo", argc, (const char **)argv, long_options, 0);
590
591         while((opt = poptGetNextOpt(pc)) != -1) {
592                 if (got_command) {
593                         fprintf(stderr, "No more than one command may be specified "
594                                 "at once.\n");
595                         exit(1);
596                 }
597                 got_command = True;
598         }
599
600         pc = poptGetContext(NULL, argc, (const char **)argv, long_options, 
601                             POPT_CONTEXT_KEEP_FIRST);
602
603         while((opt = poptGetNextOpt(pc)) != -1) {
604                 switch (opt) {
605                 case 'h':
606                         usage();
607                         exit(0);
608                 case 'u':
609                         if (!print_domain_users()) {
610                                 printf("Error looking up domain users\n");
611                                 return 1;
612                         }
613                         break;
614                 case 'g':
615                         if (!print_domain_groups()) {
616                                 printf("Error looking up domain groups\n");
617                                 return 1;
618                         }
619                         break;
620                 case 's':
621                         if (!wbinfo_lookupsid(string_arg)) {
622                                 printf("Could not lookup sid %s\n", string_arg);
623                                 return 1;
624                         }
625                         break;
626                 case 'n':
627                         if (!wbinfo_lookupname(string_arg)) {
628                                 printf("Could not lookup name %s\n", string_arg);
629                                 return 1;
630                         }
631                         break;
632                 case 'U':
633                         if (!wbinfo_uid_to_sid(int_arg)) {
634                                 printf("Could not convert uid %d to sid\n", int_arg);
635                                 return 1;
636                         }
637                         break;
638                 case 'G':
639                         if (!wbinfo_gid_to_sid(int_arg)) {
640                                 printf("Could not convert gid %d to sid\n",
641                                        int_arg);
642                                 return 1;
643                         }
644                         break;
645                 case 'S':
646                         if (!wbinfo_sid_to_uid(string_arg)) {
647                                 printf("Could not convert sid %s to uid\n",
648                                        string_arg);
649                                 return 1;
650                         }
651                         break;
652                 case 'Y':
653                         if (!wbinfo_sid_to_gid(string_arg)) {
654                                 printf("Could not convert sid %s to gid\n",
655                                        string_arg);
656                                 return 1;
657                         }
658                         break;
659                 case 't':
660                         if (!wbinfo_check_secret()) {
661                                 printf("Could not check secret\n");
662                                 return 1;
663                         }
664                         break;
665                 case 'm':
666                         if (!wbinfo_list_domains()) {
667                                 printf("Could not list trusted domains\n");
668                                 return 1;
669                         }
670                         break;
671                 case 'r':
672                         if (!wbinfo_get_usergroups(string_arg)) {
673                                 printf("Could not get groups for user %s\n", 
674                                        string_arg);
675                                 return 1;
676                         }
677                         break;
678                 case 'a': {
679                         BOOL got_error = False;
680
681                         if (!wbinfo_auth(string_arg)) {
682                                 printf("Could not authenticate user %s with "
683                                        "plaintext password\n", string_arg);
684                                 got_error = True;
685                         }
686
687                         if (!wbinfo_auth_crap(string_arg)) {
688                                 printf("Could not authenticate user %s with "
689                                        "challenge/response\n", string_arg);
690                                 got_error = True;
691                         }
692                         
693                         if (got_error)
694                                 return 1;
695                         break;
696                 }
697                 case 'p': {
698
699                         if (!wbinfo_ping()) {
700                                 printf("could not ping winbindd!\n");
701                                 return 1;
702                         }
703                         break;
704                 }
705                 case OPT_SET_AUTH_USER:
706                         if (!(wbinfo_set_auth_user(string_arg))) {
707                                 return 1;
708                         }
709                         break;
710                 default:
711                         fprintf(stderr, "Invalid option\n");
712                         usage();
713                         return 1;
714                 }
715         }
716
717         /* Clean exit */
718
719         return 0;
720 }