1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
14 */
15
16
17 #include <stdio.h>
18 #include <libintl.h>
19 #include <stdlib.h>
20 #include <strings.h>
21 #include <err.h>
22 #include <ads/dsgetdc.h>
23 #include <smb/nterror.h>
24 #include <uuid/uuid.h>
25
26
27 static void dclist_usage(void);
28 static int cmd_dclist(char *);
29 static void dcname_usage(void);
30 static int cmd_dcname(char *);
31 static void dsgetdc_usage(void);
32 static int cmd_dsgetdc(char *);
33 static void dsgetdcname_usage(void);
34 static int cmd_dsgetdcname(char *);
35 static void kick_usage(void);
36 static int cmd_kick(char *);
37 static void help(void);
38
39 typedef int cmd_fn_t (char *);
40 typedef void cmd_usage_t (void);
41
42
43 static struct commands {
44 const char *name; /* name of subcommand */
45 cmd_fn_t *fn; /* pointer to subcommand handler function */
46 cmd_usage_t *usage; /* pointer to subcommand help function */
47 int optreq; /* does this have a required optval */
48 } commands[] = {
49 {"dclist", cmd_dclist, dclist_usage, 0},
50 {"dcname", cmd_dcname, dcname_usage, 0},
51 {"dsgetdc", cmd_dsgetdc, dsgetdc_usage, 0},
52 {"dsgetdcname", cmd_dsgetdcname, dsgetdcname_usage, 0},
53 {"kick", cmd_kick, kick_usage, 0},
54 {NULL, NULL, NULL, 0}
55 };
56
57
58 /*
59 * lookupcmd
60 */
61 static struct commands *
lookupcmd(const char * name)62 lookupcmd(const char *name)
63 {
64 struct commands *cmd;
65
66 for (cmd = commands; cmd->name; cmd++) {
67 if (strcasecmp(cmd->name, name) == 0)
68 return (cmd);
69 }
70 return (NULL);
71 }
72
73 /*
74 * dclist
75 */
76 static void
dclist_usage(void)77 dclist_usage(void)
78 {
79 (void) printf(gettext("usage: nltest dclist... \n"));
80 exit(1);
81 }
82
83 /* ARGSUSED */
84 static int
cmd_dclist(char * optval)85 cmd_dclist(char *optval)
86 {
87 (void) printf("cmd_dclist() \n");
88 return (0);
89 }
90
91 /*
92 * dcname
93 */
94 static void
dcname_usage(void)95 dcname_usage(void)
96 {
97 (void) printf(gettext("usage: nltest dcname... \n"));
98 exit(1);
99 }
100
101 /* ARGSUSED */
102 static int
cmd_dcname(char * optval)103 cmd_dcname(char *optval)
104 {
105 (void) printf("cmd_dcname() \n");
106 return (0);
107 }
108
109 /*
110 * dsgetdc
111 */
112 static void
dsgetdc_usage(void)113 dsgetdc_usage(void)
114 {
115 (void) printf(gettext("usage: nltest dsgetdc... \n"));
116 exit(1);
117 }
118
119 /* ARGSUSED */
120 static int
cmd_dsgetdc(char * optval)121 cmd_dsgetdc(char *optval)
122 {
123 (void) printf("cmd_dsgetdc() \n");
124 return (0);
125 }
126
127 /*
128 * dsgetdcname
129 */
130 static void
dsgetdcname_usage(void)131 dsgetdcname_usage(void)
132 {
133 (void) printf(gettext("usage: nltest dsgetdcname domainname \n"));
134 exit(1);
135 }
136
137 static int
cmd_dsgetdcname(char * domname)138 cmd_dsgetdcname(char *domname)
139 {
140 char uuid_buf[UUID_PRINTABLE_STRING_LENGTH];
141 int err = 0;
142 char *atype;
143 DOMAIN_CONTROLLER_INFO *dcinfo;
144
145 if (domname != NULL)
146 (void) printf(" Domain name supplied: %s \n", domname);
147
148 err = DsGetDcName(NULL, domname, NULL, NULL, 0, &dcinfo);
149
150 switch (err) {
151 case 0:
152 break;
153 case ERROR_NO_SUCH_DOMAIN:
154 (void) printf("Domain controller not found.\n");
155 (void) printf("See: /var/run/idmap/discovery.log\n");
156 exit(1);
157 default:
158 (void) printf("Unexpected error %d\n", err);
159 exit(1);
160 }
161
162 switch (dcinfo->DomainControllerAddressType) {
163 case DS_INET_ADDRESS:
164 atype = "inet";
165 break;
166 case DS_NETBIOS_ADDRESS:
167 atype = "netbios";
168 break;
169 default:
170 atype = "?";
171 break;
172 }
173
174 uuid_unparse(dcinfo->DomainGuid, uuid_buf);
175
176 (void) printf("Data Returned from DsGetDcName() call: \n");
177 (void) printf(" DC Name: %s \n", dcinfo->DomainControllerName);
178 (void) printf(" DC Addr: %s \n", dcinfo->DomainControllerAddress);
179 (void) printf(" DC Addr Type: %s \n", atype);
180 (void) printf(" Domain Name: %s \n", dcinfo->DomainName);
181 (void) printf(" Domain GUID: %s \n", uuid_buf);
182 (void) printf(" DNS Forest Name: %s \n", dcinfo->DnsForestName);
183 (void) printf(" Flags: 0x%x \n", dcinfo->Flags);
184 (void) printf(" DC Site Name: %s \n", dcinfo->DcSiteName);
185 (void) printf(" Client Site Name: %s \n", dcinfo->ClientSiteName);
186
187 return (0);
188 }
189
190 /*
191 * kick
192 */
193 static void
kick_usage(void)194 kick_usage(void)
195 {
196 (void) printf(gettext("usage: nltest /KICK \n"));
197 exit(1);
198 }
199
200
201 static int
cmd_kick(char * domname)202 cmd_kick(char *domname)
203 {
204 int flags = 0;
205 int result;
206
207 result = _DsForceRediscovery(domname, flags);
208
209 return (result);
210 }
211
212 /*
213 * help functions
214 */
215
216 static void
help(void)217 help(void) {
218 (void) printf("\n");
219 /*
220 * TODO: We may want to revise this help text. It's basically
221 * a copy-paste from:
222 * http://technet.microsoft.com/en-us/library/cc731935.aspx
223 */
224 (void) printf(gettext("usage: %s /subcommand\n"),
225 (char *)getexecname());
226 (void) printf(gettext("where subcommands are:\n"
227 #if 0 /* not yet */
228 " dclist Lists all domain controllers in the domain.\n"
229 " dcname Lists the PDC or PDC emulator.\n"
230 " dsgetdc Queries DNS server for list of DCs and"
231 " their IP addresses and contacts each DC to check"
232 " for connectivity.\n"
233 #endif
234 " dsgetdcname returns the name of a domain controller in a"
235 " specified domain\n"
236 " help display help on specified subcommand\n"
237 " kick trigger domain controller re-discovery\n"
238 "\n"));
239 exit(1);
240 }
241
242 int
main(int argc,char * argv[])243 main(int argc, char *argv[])
244 {
245 struct commands *cmd;
246 int err = 0;
247 char *option_cmd = NULL;
248 char *arg;
249 char *p;
250 char *optname;
251 char *optval = NULL;
252 int i;
253 int optind = 1;
254
255 /*
256 * Parse options.
257 */
258 while (optind < argc) {
259 arg = argv[optind];
260 optname = NULL;
261 optval = NULL;
262
263 /* Is this an option? */
264 if (arg[0] == '/') {
265 optname = arg + 1;
266 optind++;
267
268 /*
269 * May have /optname:value
270 */
271 if ((p = strchr(optname, ':')) != NULL) {
272 *p++ = '\0';
273 optval = p;
274 }
275 } else if (arg[0] == '-' && arg[1] == '-') {
276 optname = arg + 2;
277 optind++;
278
279 /*
280 * May have --optname=value
281 */
282 if ((p = strchr(optname, '=')) != NULL) {
283 *p++ = '\0';
284 optval = p;
285 }
286 } else {
287 /* Not an option. Stop parsing. */
288 break;
289 }
290
291 /*
292 * Handle each optname (and maybe its optval)
293 * Might put this logic in a table of options.
294 * (including a flag for "optval required",
295 * so that check could be factored out)
296 */
297 for (cmd = commands; cmd->name; cmd++) {
298 if (!strcasecmp(optname, cmd->name)) {
299 /* cmd->name requires an optval */
300 if (optval == NULL && optind < argc)
301 optval = argv[optind++];
302
303 if (optval == NULL && cmd->optreq > 0) {
304 (void) fprintf(stderr,
305 "%s: option %s requires a value\n",
306 argv[0], optname);
307 return (1);
308 }
309 option_cmd = optname;
310 }
311 }
312 }
313
314 /*
315 * Handle remaining non-option arguments
316 */
317 for (i = optind; i < argc; i++) {
318 (void) printf("arg: %s\n", argv[i]);
319 }
320
321 if (option_cmd == NULL)
322 help();
323
324 cmd = lookupcmd(option_cmd);
325 if (cmd == NULL)
326 err = 1;
327 else
328 err = cmd->fn(optval);
329
330 return (err);
331 }
332