This is the 'winbind default domain' patch from Alexander Bokovoy
[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         /*
298          * Don't do the lookup if the name has no separator.
299          */
300  
301         if (!strchr(name, get_winbind_separator()))
302                 return False;
303
304         /* Send off request */
305
306         ZERO_STRUCT(request);
307         ZERO_STRUCT(response);
308
309         fstrcpy(request.data.name, name);
310         if (winbindd_request(WINBINDD_LOOKUPNAME, &request, &response) !=
311             NSS_STATUS_SUCCESS) {
312                 return False;
313         }
314
315         /* Display response */
316
317         printf("%s %d\n", response.data.sid.sid, response.data.sid.type);
318
319         return True;
320 }
321
322 /* Authenticate a user with a plaintext password */
323
324 static BOOL wbinfo_auth(char *username)
325 {
326         struct winbindd_request request;
327         struct winbindd_response response;
328         NSS_STATUS result;
329         char *p;
330
331         /* Send off request */
332
333         ZERO_STRUCT(request);
334         ZERO_STRUCT(response);
335
336         p = strchr(username, '%');
337
338         if (p) {
339                 *p = 0;
340                 fstrcpy(request.data.auth.user, username);
341                 fstrcpy(request.data.auth.pass, p + 1);
342                 *p = '%';
343         } else
344                 fstrcpy(request.data.auth.user, username);
345
346         result = winbindd_request(WINBINDD_PAM_AUTH, &request, &response);
347
348         /* Display response */
349
350         printf("plaintext password authentication %s\n", 
351                (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed");
352
353         return result == NSS_STATUS_SUCCESS;
354 }
355
356 /* Authenticate a user with a challenge/response */
357
358 static BOOL wbinfo_auth_crap(char *username)
359 {
360         struct winbindd_request request;
361         struct winbindd_response response;
362         NSS_STATUS result;
363         fstring name_user;
364         fstring name_domain;
365         fstring pass;
366         char *p;
367
368         /*
369          * Don't do the lookup if the name has no separator.
370          */
371  
372         /* Send off request */
373
374         ZERO_STRUCT(request);
375         ZERO_STRUCT(response);
376
377         p = strchr(username, '%');
378
379         if (p) {
380                 *p = 0;
381                 fstrcpy(pass, p + 1);
382         }
383                 
384         parse_wbinfo_domain_user(username, name_domain, name_user);
385
386         fstrcpy(request.data.auth_crap.user, name_user);
387
388         fstrcpy(request.data.auth_crap.domain, name_domain);
389
390         generate_random_buffer(request.data.auth_crap.chal, 8, False);
391         
392         SMBencrypt((uchar *)pass, request.data.auth_crap.chal, 
393                    (uchar *)request.data.auth_crap.lm_resp);
394         SMBNTencrypt((uchar *)pass, request.data.auth_crap.chal,
395                      (uchar *)request.data.auth_crap.nt_resp);
396
397         request.data.auth_crap.lm_resp_len = 24;
398         request.data.auth_crap.nt_resp_len = 24;
399
400         result = winbindd_request(WINBINDD_PAM_AUTH_CRAP, &request, &response);
401
402         /* Display response */
403
404         printf("challenge/response password authentication %s\n", 
405                (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed");
406
407         return result == NSS_STATUS_SUCCESS;
408 }
409
410 /* Print domain users */
411
412 static BOOL print_domain_users(void)
413 {
414         struct winbindd_response response;
415         char *extra_data;
416         fstring name;
417
418         /* Send request to winbind daemon */
419
420         ZERO_STRUCT(response);
421
422         if (winbindd_request(WINBINDD_LIST_USERS, NULL, &response) !=
423             NSS_STATUS_SUCCESS) {
424                 return False;
425         }
426
427         /* Look through extra data */
428
429         if (!response.extra_data)
430                 return False;
431
432         extra_data = (char *)response.extra_data;
433
434         while(next_token(&extra_data, name, ",", sizeof(fstring)))
435                 printf("%s\n", name);
436         
437         SAFE_FREE(response.extra_data);
438
439         return True;
440 }
441
442 /* Print domain groups */
443
444 static BOOL print_domain_groups(void)
445 {
446         struct winbindd_response response;
447         char *extra_data;
448         fstring name;
449
450         ZERO_STRUCT(response);
451
452         if (winbindd_request(WINBINDD_LIST_GROUPS, NULL, &response) !=
453             NSS_STATUS_SUCCESS) {
454                 return False;
455         }
456
457         /* Look through extra data */
458
459         if (!response.extra_data)
460                 return False;
461
462         extra_data = (char *)response.extra_data;
463
464         while(next_token(&extra_data, name, ",", sizeof(fstring)))
465                 printf("%s\n", name);
466
467         SAFE_FREE(response.extra_data);
468         
469         return True;
470 }
471
472 /* Set the authorised user for winbindd access in secrets.tdb */
473
474 static BOOL wbinfo_set_auth_user(char *username)
475 {
476         char *password;
477
478         /* Separate into user and password */
479
480         password = strchr(username, '%');
481
482         if (password) {
483                 *password = 0;
484                 password++;
485         } else
486                 password = "";
487
488         /* Store in secrets.tdb */
489
490         if (!secrets_store(SECRETS_AUTH_USER, username, strlen(username) + 1) ||
491             !secrets_store(SECRETS_AUTH_PASSWORD, password, strlen(password) + 1)) {
492                 fprintf(stderr, "error storing authenticated user info\n");
493                 return False;
494         }
495
496         return True;
497 }
498
499 static BOOL wbinfo_ping(void)
500 {
501         NSS_STATUS result;
502         
503         result = winbindd_request(WINBINDD_PING, NULL, NULL);
504
505         /* Display response */
506
507         printf("'ping' to winbindd %s\n", 
508                (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed");
509
510         return result == NSS_STATUS_SUCCESS;
511 }
512
513 /* Print program usage */
514
515 static void usage(void)
516 {
517         printf("Usage: wbinfo -ug | -n name | -sSY sid | -UG uid/gid | -tm "
518                "| -a user%%password\n");
519         printf("\t-u\t\t\tlists all domain users\n");
520         printf("\t-g\t\t\tlists all domain groups\n");
521         printf("\t-n name\t\t\tconverts name to sid\n");
522         printf("\t-s sid\t\t\tconverts sid to name\n");
523         printf("\t-U uid\t\t\tconverts uid to sid\n");
524         printf("\t-G gid\t\t\tconverts gid to sid\n");
525         printf("\t-S sid\t\t\tconverts sid to uid\n");
526         printf("\t-Y sid\t\t\tconverts sid to gid\n");
527         printf("\t-t\t\t\tcheck shared secret\n");
528         printf("\t-m\t\t\tlist trusted domains\n");
529         printf("\t-r user\t\t\tget user groups\n");
530         printf("\t-a user%%password\tauthenticate user\n");
531         printf("\t-p 'ping' winbindd to see if it is alive\n");
532 }
533
534 /* Main program */
535
536 enum {
537         OPT_SET_AUTH_USER = 1000
538 };
539
540 int main(int argc, char **argv)
541 {
542         extern pstring global_myname;
543         int opt;
544
545         poptContext pc;
546         static char *string_arg;
547         static int int_arg;
548         BOOL got_command = False;
549
550         struct poptOption long_options[] = {
551
552                 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
553                 { "help", 'h', POPT_ARG_NONE, 0, 'h' },
554                 { "domain-users", 'u', POPT_ARG_NONE, 0, 'u' },
555                 { "domain-groups", 'g', POPT_ARG_NONE, 0, 'g' },
556                 { "name-to-sid", 'n', POPT_ARG_STRING, &string_arg, 'n' },
557                 { "sid-to-name", 's', POPT_ARG_STRING, &string_arg, 's' },
558                 { "uid-to-sid", 'U', POPT_ARG_INT, &int_arg, 'U' },
559                 { "gid-to-sid", 'G', POPT_ARG_INT, &int_arg, 'G' },
560                 { "sid-to-uid", 'S', POPT_ARG_STRING, &string_arg, 'S' },
561                 { "sid-to-gid", 'Y', POPT_ARG_STRING, &string_arg, 'Y' },
562                 { "check-secret", 't', POPT_ARG_NONE, 0, 't' },
563                 { "trusted-domains", 'm', POPT_ARG_NONE, 0, 'm' },
564                 { "user-groups", 'r', POPT_ARG_STRING, &string_arg, 'r' },
565                 { "authenticate", 'a', POPT_ARG_STRING, &string_arg, 'a' },
566                 { "set-auth-user", 0, POPT_ARG_STRING, &string_arg, OPT_SET_AUTH_USER },
567                 { "ping", 'p', POPT_ARG_NONE, 0, 'p' },
568                 { 0, 0, 0, 0 }
569         };
570
571         /* Samba client initialisation */
572
573         if (!*global_myname) {
574                 char *p;
575
576                 fstrcpy(global_myname, myhostname());
577                 p = strchr(global_myname, '.');
578                 if (p) {
579                         *p = 0;
580                 }
581         }
582
583         if (!lp_load(dyn_CONFIGFILE, True, False, False)) {
584                 fprintf(stderr, "wbinfo: error opening config file %s. Error was %s\n",
585                         dyn_CONFIGFILE, strerror(errno));
586                 exit(1);
587         }
588
589         load_interfaces();
590
591         /* Parse command line options */
592
593         if (argc == 1) {
594                 usage();
595                 return 1;
596         }
597
598         /* Parse options */
599
600         pc = poptGetContext("wbinfo", argc, (const char **)argv, long_options, 0);
601
602         while((opt = poptGetNextOpt(pc)) != -1) {
603                 if (got_command) {
604                         fprintf(stderr, "No more than one command may be specified "
605                                 "at once.\n");
606                         exit(1);
607                 }
608                 got_command = True;
609         }
610
611         pc = poptGetContext(NULL, argc, (const char **)argv, long_options, 
612                             POPT_CONTEXT_KEEP_FIRST);
613
614         while((opt = poptGetNextOpt(pc)) != -1) {
615                 switch (opt) {
616                 case 'h':
617                         usage();
618                         exit(0);
619                 case 'u':
620                         if (!print_domain_users()) {
621                                 printf("Error looking up domain users\n");
622                                 return 1;
623                         }
624                         break;
625                 case 'g':
626                         if (!print_domain_groups()) {
627                                 printf("Error looking up domain groups\n");
628                                 return 1;
629                         }
630                         break;
631                 case 's':
632                         if (!wbinfo_lookupsid(string_arg)) {
633                                 printf("Could not lookup sid %s\n", string_arg);
634                                 return 1;
635                         }
636                         break;
637                 case 'n':
638                         if (!wbinfo_lookupname(string_arg)) {
639                                 printf("Could not lookup name %s\n", string_arg);
640                                 return 1;
641                         }
642                         break;
643                 case 'U':
644                         if (!wbinfo_uid_to_sid(int_arg)) {
645                                 printf("Could not convert uid %d to sid\n", int_arg);
646                                 return 1;
647                         }
648                         break;
649                 case 'G':
650                         if (!wbinfo_gid_to_sid(int_arg)) {
651                                 printf("Could not convert gid %d to sid\n",
652                                        int_arg);
653                                 return 1;
654                         }
655                         break;
656                 case 'S':
657                         if (!wbinfo_sid_to_uid(string_arg)) {
658                                 printf("Could not convert sid %s to uid\n",
659                                        string_arg);
660                                 return 1;
661                         }
662                         break;
663                 case 'Y':
664                         if (!wbinfo_sid_to_gid(string_arg)) {
665                                 printf("Could not convert sid %s to gid\n",
666                                        string_arg);
667                                 return 1;
668                         }
669                         break;
670                 case 't':
671                         if (!wbinfo_check_secret()) {
672                                 printf("Could not check secret\n");
673                                 return 1;
674                         }
675                         break;
676                 case 'm':
677                         if (!wbinfo_list_domains()) {
678                                 printf("Could not list trusted domains\n");
679                                 return 1;
680                         }
681                         break;
682                 case 'r':
683                         if (!wbinfo_get_usergroups(string_arg)) {
684                                 printf("Could not get groups for user %s\n", 
685                                        string_arg);
686                                 return 1;
687                         }
688                         break;
689                 case 'a': {
690                         BOOL got_error = False;
691
692                         if (!wbinfo_auth(string_arg)) {
693                                 printf("Could not authenticate user %s with "
694                                        "plaintext password\n", string_arg);
695                                 got_error = True;
696                         }
697
698                         if (!wbinfo_auth_crap(string_arg)) {
699                                 printf("Could not authenticate user %s with "
700                                        "challenge/response\n", string_arg);
701                                 got_error = True;
702                         }
703                         
704                         if (got_error)
705                                 return 1;
706                         break;
707                 }
708                 case 'p': {
709
710                         if (!wbinfo_ping()) {
711                                 printf("could not ping winbindd!\n");
712                                 return 1;
713                         }
714                         break;
715                 }
716                 case OPT_SET_AUTH_USER:
717                         if (!(wbinfo_set_auth_user(string_arg))) {
718                                 return 1;
719                         }
720                         break;
721                 default:
722                         fprintf(stderr, "Invalid option\n");
723                         usage();
724                         return 1;
725                 }
726         }
727
728         /* Clean exit */
729
730         return 0;
731 }