1/* 2 * Copyright (c) 2000, Boris Popov 3 * All rights reserved. 4 * 5 * Portions Copyright (C) 2001 - 2010 Apple Inc. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Boris Popov. 18 * 4. Neither the name of the author nor the names of any co-contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 */ 35#include <sys/param.h> 36#include <sys/errno.h> 37#include <sys/stat.h> 38#include <err.h> 39#include <stdio.h> 40#include <unistd.h> 41#include <strings.h> 42#include <stdlib.h> 43#include <sysexits.h> 44 45#include <smbclient/smbclient.h> 46#include <smbclient/ntstatus.h> 47 48#include "common.h" 49#include "netshareenum.h" 50 51/* 52 * Allocate a buffer and then use CFStringGetCString to copy the c-style string 53 * into the buffer. The calling routine needs to free the buffer when done. 54 */ 55static char *CStringCreateWithCFString(CFStringRef inStr) 56{ 57 CFIndex maxLen; 58 char *str; 59 60 if (inStr == NULL) { 61 return NULL; 62 } 63 maxLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(inStr), 64 kCFStringEncodingUTF8) + 1; 65 str = malloc(maxLen); 66 if (!str) { 67 return NULL; 68 } 69 CFStringGetCString(inStr, str, maxLen, kCFStringEncodingUTF8); 70 return str; 71} 72 73/* 74 * Given a share dictionary create an array that contains the share entries in 75 * the dictionary. 76 */ 77CFArrayRef createShareArrayFromShareDictionary(CFDictionaryRef shareDict) 78{ 79 CFIndex count = 0; 80 CFArrayRef keyArray = NULL; 81 82 if (!shareDict) 83 return NULL; 84 count = CFDictionaryGetCount(shareDict); 85 86 void *shareKeys = CFAllocatorAllocate(kCFAllocatorDefault, count * sizeof(CFStringRef), 0); 87 if (shareKeys) { 88 CFDictionaryGetKeysAndValues(shareDict, (const void **)shareKeys, NULL); 89 keyArray = CFArrayCreate(kCFAllocatorDefault, (const void **)shareKeys, 90 count, &kCFTypeArrayCallBacks); 91 CFAllocatorDeallocate(kCFAllocatorDefault, shareKeys); 92 } 93 94 return keyArray; 95} 96 97int 98cmd_view(int argc, char *argv[]) 99{ 100 const char *url = NULL; 101 int opt; 102 SMBHANDLE serverConnection = NULL; 103 uint64_t options = 0; 104 NTSTATUS status; 105 int error; 106 CFDictionaryRef shareDict= NULL; 107 108 while ((opt = getopt(argc, argv, "ANGgaf")) != EOF) { 109 switch(opt){ 110 case 'A': 111 options |= kSMBOptionSessionOnly; 112 break; 113 case 'N': 114 options |= kSMBOptionNoPrompt; 115 break; 116 case 'G': 117 options |= kSMBOptionAllowGuestAuth; 118 break; 119 case 'g': 120 if (options & kSMBOptionOnlyAuthMask) 121 view_usage(); 122 options |= kSMBOptionUseGuestOnlyAuth; 123 options |= kSMBOptionNoPrompt; 124 break; 125 case 'a': 126 if (options & kSMBOptionOnlyAuthMask) 127 view_usage(); 128 options |= kSMBOptionUseAnonymousOnlyAuth; 129 options |= kSMBOptionNoPrompt; 130 break; 131 case 'f': 132 options |= kSMBOptionForceNewSession; 133 break; 134 default: 135 view_usage(); 136 /*NOTREACHED*/ 137 } 138 } 139 140 if (optind >= argc) 141 view_usage(); 142 url = argv[optind]; 143 argc -= optind; 144 /* One more check to make sure we have the correct number of arguments */ 145 if (argc != 1) 146 view_usage(); 147 148 status = SMBOpenServerEx(url, &serverConnection, options); 149 /* 150 * SMBOpenServerEx now sets errno, so err will work correctly. We change 151 * the string based on the NTSTATUS Error. 152 */ 153 if (!NT_SUCCESS(status)) { 154 /* This routine will exit the program */ 155 ntstatus_to_err(status); 156 } 157 if (options & kSMBOptionSessionOnly) { 158 fprintf(stdout, "Authenticate successfully with %s\n", url); 159 goto done; 160 } 161 fprintf(stdout, "%-48s%-8s%s\n", "Share", "Type", "Comments"); 162 fprintf(stdout, "-------------------------------\n"); 163 164 error = smb_netshareenum(serverConnection, &shareDict, FALSE); 165 if (error) { 166 errno = error; 167 SMBReleaseServer(serverConnection); 168 err(EX_IOERR, "unable to list resources"); 169 } else { 170 CFArrayRef shareArray = createShareArrayFromShareDictionary(shareDict); 171 CFStringRef shareStr, shareTypeStr, commentStr; 172 CFDictionaryRef theDict; 173 CFIndex ii; 174 char *share, *sharetype, *comments; 175 176 for (ii=0; shareArray && (ii < CFArrayGetCount(shareArray)); ii++) { 177 shareStr = CFArrayGetValueAtIndex(shareArray, ii); 178 /* Should never happen, but just to be safe */ 179 if (shareStr == NULL) { 180 continue; 181 } 182 theDict = CFDictionaryGetValue(shareDict, shareStr); 183 /* Should never happen, but just to be safe */ 184 if (theDict == NULL) { 185 continue; 186 } 187 shareTypeStr = CFDictionaryGetValue(theDict, kNetShareTypeStrKey); 188 commentStr = CFDictionaryGetValue(theDict, kNetCommentStrKey); 189 190 share = CStringCreateWithCFString(shareStr); 191 sharetype = CStringCreateWithCFString(shareTypeStr); 192 comments = CStringCreateWithCFString(commentStr); 193 fprintf(stdout, "%-48s%-8s%s\n", share ? share : "", 194 sharetype ? sharetype : "", comments ? comments : ""); 195 free(share); 196 free(sharetype); 197 free(comments); 198 } 199 if (shareArray) { 200 fprintf(stdout, "\n%ld shares listed\n", CFArrayGetCount(shareArray)); 201 CFRelease(shareArray); 202 } else { 203 fprintf(stdout, "\n0 shares listed\n"); 204 } 205 if (shareDict) { 206 CFRelease(shareDict); 207 } 208 } 209done: 210 SMBReleaseServer(serverConnection); 211 return 0; 212} 213 214 215void 216view_usage(void) 217{ 218 fprintf(stderr, "usage: smbutil view [connection options] //" 219 "[domain;][user[:password]@]" 220 "server\n"); 221 222 fprintf(stderr, "where options are:\n" 223 " -A authorize only\n" 224 " -N don't prompt for a password\n" 225 " -G allow guest access\n" 226 " -g authorize with guest only\n" 227 " -a authorize with anonymous only\n" 228 " -f don't share session\n"); 229 exit(1); 230}