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 * 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 78 dclist_usage(void) 79 { 80 (void) printf(gettext("usage: nltest dclist... \n")); 81 exit(1); 82 } 83 84 /* ARGSUSED */ 85 static int 86 cmd_dclist(char *optval) 87 { 88 (void) printf("cmd_dclist() \n"); 89 return (0); 90 } 91 92 /* 93 * dcname 94 */ 95 static void 96 dcname_usage(void) 97 { 98 (void) printf(gettext("usage: nltest dcname... \n")); 99 exit(1); 100 } 101 102 /* ARGSUSED */ 103 static int 104 cmd_dcname(char *optval) 105 { 106 (void) printf("cmd_dcname() \n"); 107 return (0); 108 } 109 110 /* 111 * dsgetdc 112 */ 113 static void 114 dsgetdc_usage(void) 115 { 116 (void) printf(gettext("usage: nltest dsgetdc... \n")); 117 exit(1); 118 } 119 120 /* ARGSUSED */ 121 static int 122 cmd_dsgetdc(char *optval) 123 { 124 (void) printf("cmd_dsgetdc() \n"); 125 return (0); 126 } 127 128 /* 129 * dsgetdcname 130 */ 131 static void 132 dsgetdcname_usage(void) 133 { 134 (void) printf(gettext("usage: nltest dsgetdcname domainname \n")); 135 exit(1); 136 } 137 138 static int 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 197 kick_usage(void) 198 { 199 (void) printf(gettext("usage: nltest /KICK \n")); 200 exit(1); 201 } 202 203 204 static int 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 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 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