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