/* * Copyright (c) 2001 - 2010 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ #include #include #include #include #include #include #include #include #include #include #include #include #include "common.h" static const char *nb_name_type_string(uint8_t nbType, uint16_t nbFlags) { switch (nbType) { case kNetBIOSWorkstationService: if (nbFlags & NBNS_GROUP_NAME) { return "Domain Name"; } else { return "Workstation Service"; } break; case kNetBIOSMSBrowseService: if (nbFlags & NBNS_GROUP_NAME) { return "Master Browser"; } else { return "Messenger Service"; } break; case kNetBIOSMessengerService: return "Messenger Service"; break; case kNetBIOSRASServerService: return "RAS Server Service"; break; case kNetBIOSDomainMasterBrowser: return "Domain Master Browser"; break; case kNetBIOSDomainControllers: return "Domain Controllers"; break; case kNetBIOSMasterBrowser: return "Master Browser"; break; case kNetBIOSBrowserServiceElections: return "Browser Service Elections"; break; case kNetBIOSNetDDEService: return "NetDDE Service"; break; case kNetBIOSFileServerService: return "File/Print Server Service"; break; case kNetBIOSRASClientService: return "RAS Client Service"; break; case kNetBIOSMSExchangeInterchange: return "Microsoft Exchange Interchange"; break; case kNetBIOSMicrosoftExchangeStore: return "Microsoft Exchange Store"; break; case kNetBIOSMicrosoftExchangeDirectory: return "Microsoft Exchange Directory"; break; case kNetBIOSModemSharingServerService: return "Modem Sharing Server Service"; break; case kNetBIOSModemSharingClientService: return "Modem Sharing Client Service"; break; case kNetBIOSSMSClientsRemoteControl: return "SMS Clients Remote Control"; break; case kNetBIOSSMSAdminRemoteControlTool: return "SMS Administrators Remote Control Tool"; break; case kNetBIOSSMSClientsRemoteChat: return "SMS Clients Remote Chat"; break; case kNetBIOSDECPathworks: return "DEC Pathworks"; break; case kNetBIOSMicrosoftExchangeIMC: return "Microsoft Exchange MTA"; break; case kNetBIOSMicrosoftExchangeMTA: return "Microsoft Exchange IMC"; break; case kNetBIOSNetworkMonitorAgent: return "Network Monitor Agent"; break; case kNetBIOSNetworkMonitorApplication: return "Network Monitor Application"; break; default: return ""; break; } } /* * Convert the NetBIOS name to a UTF8 display name. */ static char * getDisplayName(const char *name, Boolean escapeNames) { char *displayName = SMBConvertFromCodePageToUTF8(name); CFStringRef nameRef = NULL; CFStringRef newNameRef = NULL; if (!escapeNames) { return displayName; } /* Get a CFString */ if (displayName) { nameRef = CFStringCreateWithCString(kCFAllocatorDefault, displayName, kCFStringEncodingUTF8); } /* Escape out the CFString */ if (nameRef) { newNameRef = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, nameRef, CFSTR(" "), CFSTR(""), kCFStringEncodingUTF8); } /* Now create an esacpe out c style string */ if (newNameRef) { int maxlen = (int)CFStringGetLength(newNameRef)+1; free(displayName); displayName = malloc(maxlen); if (displayName) { CFStringGetCString(newNameRef, displayName, maxlen, kCFStringEncodingUTF8); } } if (nameRef) { CFRelease(nameRef); } if (newNameRef) { CFRelease(newNameRef); } return displayName; } int cmd_status(int argc, char *argv[]) { uint32_t ii; int opt; char * displayName; char *hostname; struct NodeStatusInfo *listInfo, *startInfo; uint32_t count = 0; Boolean displayAllNames= FALSE; Boolean escapeNames= FALSE; if (argc < 2) { status_usage(); } while ((opt = getopt(argc, argv, "ae")) != EOF) { switch(opt) { case 'a': displayAllNames = TRUE; break; case 'e': escapeNames = TRUE; break; default: status_usage(); /*NOTREACHED*/ } } if (optind >= argc) { status_usage(); } hostname = argv[argc - 1]; startInfo = listInfo = SMBGetNodeStatus(hostname, &count); if (startInfo == NULL) { if (errno == EHOSTUNREACH) { err(EX_NOHOST, "unable to get status for hostname %s", hostname); } else { err(EX_NOHOST, "unable to resolve hostname %s", hostname); } } for (ii=0; ii < count; ii++, listInfo++) { struct sockaddr_in *in4 = NULL; struct sockaddr_in6 *in6 = NULL; char addrStr[INET6_ADDRSTRLEN+1]; /* Get an address we can display */ if (listInfo->node_storage.ss_family == AF_INET) { in4 = (struct sockaddr_in *)&listInfo->node_storage; inet_ntop(listInfo->node_storage.ss_family, &in4->sin_addr, addrStr, sizeof(addrStr)); } else if (listInfo->node_storage.ss_family == AF_INET6) { in6 = (struct sockaddr_in6 *)&listInfo->node_storage; inet_ntop(listInfo->node_storage.ss_family, &in6->sin6_addr, addrStr, sizeof(addrStr)); } else { strcpy(addrStr, "unknown address family"); } /* Didn't get any names on this address go to the next one */ if (listInfo->node_errno) { fprintf(stdout, "%s: unable to get status from %s using address %s\n", strerror(listInfo->node_errno), hostname, addrStr); continue; } fprintf(stdout, "Using IP address of %s: %s\n", hostname, addrStr); /* They want us to display all the names. */ if (displayAllNames) { struct NBResourceRecord *nbrr = listInfo->node_nbrrArray; if (nbrr) { fprintf(stdout, "%-32s %-7s %-6s Description\n", "NetBIOS Name","Number","Type"); for (ii=0; ii < listInfo->node_nbrrArrayCnt; ii++) { uint8_t nbNum; nbNum = nbrr->rrName[NetBIOS_NAME_LEN-1]; nbrr->rrName[NetBIOS_NAME_LEN-1] = 0; displayName = getDisplayName(nbrr->rrName, escapeNames); if (displayName) { fprintf(stdout, "%-32s 0x%.2x %-6s [%s]\n", displayName, nbNum, (nbrr->nbFlags & NBNS_GROUP_NAME) ? "GROUP" : "UNIQUE", nb_name_type_string(nbNum, nbrr->nbFlags)); free(displayName); } else { fprintf(stdout, "%-32s 0x%.2x %-6s [%s]\n", nbrr->rrName, nbNum, (nbrr->nbFlags & NBNS_GROUP_NAME) ? "GROUP" : "UNIQUE", nb_name_type_string(nbNum, nbrr->nbFlags)); } nbrr++; } } } else { /* Display the file server and workgroup name */ if (listInfo->node_workgroupname[0]) { displayName = getDisplayName(listInfo->node_workgroupname, escapeNames); if (displayName) { fprintf(stdout, "Workgroup: %s\n", displayName); free(displayName); } else fprintf(stdout, "Workgroup: %s\n", listInfo->node_workgroupname); } if (listInfo->node_servername[0]) { displayName = getDisplayName(listInfo->node_servername, escapeNames); if (displayName) { fprintf(stdout, "Server: %s\n", displayName); free(displayName); } else fprintf(stdout, "Server: %s\n", listInfo->node_servername); } } fprintf(stdout, "\n"); /* We have nbrrArray so free it */ if (listInfo->node_nbrrArray) { free(listInfo->node_nbrrArray); listInfo->node_nbrrArray = NULL; } } if (startInfo) { free(startInfo); } return 0; } void status_usage(void) { fprintf(stderr, "usage: smbutil status [ -ae ] hostname\n"); exit(1); }