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