r6149: Fixes bugs #2498 and 2484.
[samba.git] / source / utils / net_lookup.c
1 /* 
2    Samba Unix/Linux SMB client library 
3    net lookup command
4    Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
19
20 #include "includes.h"
21 #include "utils/net.h"
22
23 int net_lookup_usage(int argc, const char **argv)
24 {
25         d_printf(
26 "  net lookup [host] HOSTNAME[#<type>]\n\tgives IP for a hostname\n\n"
27 "  net lookup ldap [domain]\n\tgives IP of domain's ldap server\n\n"
28 "  net lookup kdc [realm]\n\tgives IP of realm's kerberos KDC\n\n"
29 "  net lookup dc [domain]\n\tgives IP of domains Domain Controllers\n\n"
30 "  net lookup master [domain|wg]\n\tgive IP of master browser\n\n"
31 );
32         return -1;
33 }
34
35 /* lookup a hostname giving an IP */
36 static int net_lookup_host(int argc, const char **argv)
37 {
38         struct in_addr ip;
39         int name_type = 0x20;
40         const char *name = argv[0];
41         char *p;
42
43         if (argc == 0) 
44                 return net_lookup_usage(argc, argv);
45
46         p = strchr_m(name,'#');
47         if (p) {
48                 *p = '\0';
49                 sscanf(++p,"%x",&name_type);
50         }
51         
52         if (!resolve_name(name, &ip, name_type)) {
53                 /* we deliberately use DEBUG() here to send it to stderr 
54                    so scripts aren't mucked up */
55                 DEBUG(0,("Didn't find %s#%02x\n", name, name_type));
56                 return -1;
57         }
58
59         d_printf("%s\n", inet_ntoa(ip));
60         return 0;
61 }
62
63 static void print_ldap_srvlist(char *srvlist)
64 {
65         char *cur, *next;
66         struct in_addr ip;
67         BOOL printit;
68
69         cur = srvlist;
70         do {
71                 next = strchr(cur,':');
72                 if (next) *next++='\0';
73                 printit = resolve_name(cur, &ip, 0x20);
74                 cur=next;
75                 next=cur ? strchr(cur,' ') :NULL;
76                 if (next)
77                         *next++='\0';
78                 if (printit)
79                         d_printf("%s:%s\n", inet_ntoa(ip), cur?cur:"");
80                 cur = next;
81         } while (next);
82 }
83                 
84
85 static int net_lookup_ldap(int argc, const char **argv)
86 {
87 #ifdef HAVE_LDAP
88         char *srvlist;
89         const char *domain;
90         int rc;
91         struct in_addr addr;
92         struct hostent *hostent;
93
94         if (argc > 0)
95                 domain = argv[0];
96         else
97                 domain = opt_target_workgroup;
98
99         DEBUG(9, ("Lookup up ldap for domain %s\n", domain));
100         rc = ldap_domain2hostlist(domain, &srvlist);
101         if ((rc == LDAP_SUCCESS) && srvlist) {
102                 print_ldap_srvlist(srvlist);
103                 return 0;
104         }
105
106         DEBUG(9, ("Looking up DC for domain %s\n", domain));
107         if (!get_pdc_ip(domain, &addr))
108                 return -1;
109
110         hostent = gethostbyaddr((char *) &addr.s_addr, sizeof(addr.s_addr),
111                                 AF_INET);
112         if (!hostent)
113                 return -1;
114
115         DEBUG(9, ("Found DC with DNS name %s\n", hostent->h_name));
116         domain = strchr(hostent->h_name, '.');
117         if (!domain)
118                 return -1;
119         domain++;
120
121         DEBUG(9, ("Looking up ldap for domain %s\n", domain));
122         rc = ldap_domain2hostlist(domain, &srvlist);
123         if ((rc == LDAP_SUCCESS) && srvlist) {
124                 print_ldap_srvlist(srvlist);
125                 return 0;
126         }
127         return -1;
128 #endif
129         DEBUG(1,("No LDAP support\n"));
130         return -1;
131 }
132
133 static int net_lookup_dc(int argc, const char **argv)
134 {
135         struct ip_service *ip_list;
136         struct in_addr addr;
137         char *pdc_str = NULL;
138         const char *domain=opt_target_workgroup;
139         int count, i;
140
141         if (argc > 0)
142                 domain=argv[0];
143
144         /* first get PDC */
145         if (!get_pdc_ip(domain, &addr))
146                 return -1;
147
148         asprintf(&pdc_str, "%s", inet_ntoa(addr));
149         d_printf("%s\n", pdc_str);
150
151         if (!get_sorted_dc_list(domain, &ip_list, &count, False)) {
152                 SAFE_FREE(pdc_str);
153                 return 0;
154         }
155         for (i=0;i<count;i++) {
156                 char *dc_str = inet_ntoa(ip_list[i].ip);
157                 if (!strequal(pdc_str, dc_str))
158                         d_printf("%s\n", dc_str);
159         }
160         SAFE_FREE(pdc_str);
161         return 0;
162 }
163
164 static int net_lookup_master(int argc, const char **argv)
165 {
166         struct in_addr master_ip;
167         const char *domain=opt_target_workgroup;
168
169         if (argc > 0)
170                 domain=argv[0];
171
172         if (!find_master_ip(domain, &master_ip))
173                 return -1;
174         d_printf("%s\n", inet_ntoa(master_ip));
175         return 0;
176 }
177
178 static int net_lookup_kdc(int argc, const char **argv)
179 {
180 #ifdef HAVE_KRB5
181         krb5_error_code rc;
182         krb5_context ctx;
183         struct sockaddr_in *addrs;
184         int num_kdcs,i;
185         krb5_data realm;
186         char **realms;
187
188         rc = krb5_init_context(&ctx);
189         if (rc) {
190                 DEBUG(1,("krb5_init_context failed (%s)\n", 
191                          error_message(rc)));
192                 return -1;
193         }
194
195         if (argc>0) {
196                 realm.data = CONST_DISCARD(krb5_pointer, argv[0]);
197                 realm.length = strlen(argv[0]);
198         } else if (lp_realm() && *lp_realm()) {
199                 realm.data = (krb5_pointer) lp_realm();
200                 realm.length = strlen(realm.data);
201         } else {
202                 rc = krb5_get_host_realm(ctx, NULL, &realms);
203                 if (rc) {
204                         DEBUG(1,("krb5_gethost_realm failed (%s)\n",
205                                  error_message(rc)));
206                         return -1;
207                 }
208                 realm.data = (krb5_pointer) *realms;
209                 realm.length = strlen(realm.data);
210         }
211
212         rc = krb5_locate_kdc(ctx, &realm, (struct sockaddr **) &addrs, &num_kdcs, 0);
213         if (rc) {
214                 DEBUG(1, ("krb5_locate_kdc failed (%s)\n", error_message(rc)));
215                 return -1;
216         }
217         for (i=0;i<num_kdcs;i++)
218                 if (addrs[i].sin_family == AF_INET) 
219                         d_printf("%s:%hd\n", inet_ntoa(addrs[i].sin_addr),
220                                  ntohs(addrs[i].sin_port));
221         return 0;
222
223 #endif  
224         DEBUG(1, ("No kerberos support\n"));
225         return -1;
226 }
227
228
229 /* lookup hosts or IP addresses using internal samba lookup fns */
230 int net_lookup(int argc, const char **argv)
231 {
232         int i;
233
234         struct functable table[] = {
235                 {"HOST", net_lookup_host},
236                 {"LDAP", net_lookup_ldap},
237                 {"DC", net_lookup_dc},
238                 {"MASTER", net_lookup_master},
239                 {"KDC", net_lookup_kdc},
240                 {NULL, NULL}
241         };
242
243         if (argc < 1) {
244                 d_printf("\nUsage: \n");
245                 return net_lookup_usage(argc, argv);
246         }
247         for (i=0; table[i].funcname; i++) {
248                 if (StrCaseCmp(argv[0], table[i].funcname) == 0)
249                         return table[i].fn(argc-1, argv+1);
250         }
251
252         /* Default to lookup a hostname so 'net lookup foo#1b' can be 
253            used instead of 'net lookup host foo#1b'.  The host syntax
254            is a bit confusing as non #00 names can't really be 
255            considered hosts as such. */
256
257         return net_lookup_host(argc, argv);
258 }