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