/* * SMBNetFsTreeConnectForEnumerateShares * * When enumerating shares we need a IPC$ tree connection. This is really only * need by the old RAP calls, since the DCE/RPC code will create a whole new * session. */ int32_t SMBNetFsTreeConnectForEnumerateShares(SMBHANDLE inConnection) { int error = 0; void *hContext = NULL; SMBServerContext(inConnection, &hContext); error = smb_ctx_setshare(hContext, "IPC$"); if (!error) { error = smb_share_connect(hContext); } return error; }
int cmd_view(int argc, char *argv[]) { struct smb_ctx sctx, *ctx = &sctx; struct smb_share_info_1 *rpbuf, *ep; char *cp; u_int16_t type; int error, opt, bufsize, i, entries, total; if (argc < 2) view_usage(); if (smb_ctx_init(ctx, argc, argv, SMBL_VC, SMBL_VC, SMB_ST_ANY) != 0) exit(1); if (smb_ctx_readrc(ctx) != 0) exit(1); if (smb_rc) rc_close(smb_rc); while ((opt = getopt(argc, argv, STDPARAM_OPT)) != EOF) { switch(opt){ case STDPARAM_ARGS: error = smb_ctx_opt(ctx, opt, optarg); if (error) exit(1); break; default: view_usage(); /*NOTREACHED*/ } } #ifdef APPLE if (loadsmbvfs()) errx(EX_OSERR, "SMB filesystem is not available"); #endif smb_ctx_setshare(ctx, "IPC$", SMB_ST_ANY); if (smb_ctx_resolve(ctx) != 0) exit(1); error = smb_ctx_lookup(ctx, SMBL_SHARE, SMBLK_CREATE); if (error) { smb_error("could not login to server %s", error, ctx->ct_ssn.ioc_srvname); exit(1); } printf("Share Type Comment\n"); printf("-------------------------------\n"); bufsize = 0xffe0; /* samba notes win2k bug with 65535 */ rpbuf = malloc(bufsize); error = smb_rap_NetShareEnum(ctx, 1, rpbuf, bufsize, &entries, &total); if (error && error != (SMB_ERROR_MORE_DATA | SMB_RAP_ERROR)) { smb_error("unable to list resources", error); exit(1); } for (ep = rpbuf, i = 0; i < entries; i++, ep++) { type = letohs(ep->shi1_type); cp = (char*)rpbuf + ep->shi1_remark; printf("%-12s %-10s %s\n", ep->shi1_netname, shtype[min(type, sizeof shtype / sizeof(char *) - 1)], ep->shi1_remark ? nls_str_toloc(cp, cp) : ""); } printf("\n%d shares listed from %d available\n", entries, total); free(rpbuf); return 0; }
NTSTATUS SMBOpenServerWithMountPoint( const char * pTargetMountPath, const char * pTargetTreeName, SMBHANDLE * outConnection, uint64_t options) { NTSTATUS status; int err; void * hContext; struct statfs statbuf; *outConnection = NULL; status = SMBLibraryInit(); if (!NT_SUCCESS(status)) { goto done; } /* Need to get the mount from name, use that as the URL */ err = statfs(pTargetMountPath, &statbuf); if (err) { status = STATUS_OBJECT_PATH_NOT_FOUND; goto done; } status = SMBAllocateServer(outConnection, statbuf.f_mntfromname); if (!NT_SUCCESS(status)) { goto done; } status = SMBServerContext(*outConnection, &hContext); if (!NT_SUCCESS(status)) { goto done; } /* Need to clear out the user name field */ smb_ctx_setuser(hContext, ""); err = findMountPointVC(hContext, pTargetMountPath); if (err) { status = STATUS_OBJECT_NAME_NOT_FOUND; errno = err; goto done; } if (options & kSMBOptionSessionOnly) { goto done; } /* No tree name, let's assume that the caller means IPC$ */ if (!pTargetTreeName) { pTargetTreeName = "IPC$"; } err = smb_ctx_setshare(hContext, pTargetTreeName); if (err) { if (err == ENAMETOOLONG) { status = STATUS_NAME_TOO_LONG; } else { status = STATUS_NO_MEMORY; } errno = err; goto done; } /* OK, now we have a virtual circuit but no tree connection yet. */ err = smb_share_connect((*outConnection)->context); if (err) { status = STATUS_BAD_NETWORK_NAME; errno = err; goto done; } status = STATUS_SUCCESS; done: if ((!NT_SUCCESS(status)) && *outConnection) { SMBReleaseServer(*outConnection); *outConnection = NULL; } return status; }
NTSTATUS SMBOpenServerEx( const char * targetServer, SMBHANDLE * outConnection, uint64_t options) { NTSTATUS status; int err; void * hContext; CFMutableDictionaryRef netfsOptions = NULL; CFDictionaryRef ServerParams = NULL; *outConnection = NULL; status = SMBLibraryInit(); if (!NT_SUCCESS(status)) { goto done; } netfsOptions = SMBCreateDefaultOptions(options); if (netfsOptions == NULL) { status = STATUS_NO_MEMORY; goto done; } status = SMBAllocateServer(outConnection, targetServer); if (!NT_SUCCESS(status)) { goto done; } status = SMBServerContext(*outConnection, &hContext); if (!NT_SUCCESS(status)) { goto done; } err = smb_get_server_info(hContext, NULL, netfsOptions, &ServerParams); if (err) { /* XXX map real NTSTATUS code */ status = STATUS_CONNECTION_REFUSED; errno = err; goto done; } /* * They didn't set the force new session option and we have a shared session, * then we are done. We have a connection and we are authenticated. */ if (!(options & kSMBOptionForceNewSession) && (((struct smb_ctx *)hContext)->ct_vc_shared)) { goto authDone; } /* * They have guest as the username in the url, then they want us to * force guest access. */ if (((struct smb_ctx *)hContext)->ct_setup.ioc_userflags & SMBV_GUEST_ACCESS) { options |= kSMBOptionUseGuestOnlyAuth; } /* Connect using Guest Access only */ if (options & kSMBOptionUseGuestOnlyAuth) { status = SMBServerConnect(*outConnection, NULL, netfsOptions, kSMBAuthTypeGuest); goto authDone; } /* Connect using Anonymous Access only */ if (options & kSMBOptionUseAnonymousOnlyAuth) { status = SMBServerConnect(*outConnection, NULL, netfsOptions, kSMBAuthTypeAnonymous); goto authDone; } /* Attempt an authenticated connect, could be kerberos or ntlm. */ status = SMBServerConnect(*outConnection, NULL, netfsOptions, kSMBAuthTypeAuthenticated); if (NT_SUCCESS(status)) { goto authDone; } /* See if we need to prompt for a password */ if (SMBPasswordPrompt(*outConnection, options)) { /* Attempt an authenticated connect again , could be kerberos or ntlm. */ status = SMBServerConnect(*outConnection, NULL, netfsOptions, kSMBAuthTypeAuthenticated); if (NT_SUCCESS(status)) { goto authDone; } } /* Kerberos and NTLM failed, attempt Guest access if option set */ if (options & kSMBOptionAllowGuestAuth) { status = SMBServerConnect(*outConnection, NULL, netfsOptions, kSMBAuthTypeGuest); if (NT_SUCCESS(status)) { goto authDone; } } /* Kerberos and NTLM failed, attempt Anonymous access if option set */ if (options & kSMBOptionAllowAnonymousAuth) { status = SMBServerConnect(*outConnection, NULL, netfsOptions, kSMBAuthTypeAnonymous); if (NT_SUCCESS(status)) { goto authDone; } } authDone: if (!NT_SUCCESS(status)) { goto done; } if (options & kSMBOptionSessionOnly) { goto done; } /* * If the target doesn't contain a share name, let's assume that the * caller means IPC$, unless a share name is required. */ if (!((struct smb_ctx *)hContext)->ct_origshare) { err = smb_ctx_setshare(hContext, "IPC$"); if (err) { if (err == ENAMETOOLONG) { status = STATUS_NAME_TOO_LONG; } else { status = STATUS_NO_MEMORY; } errno = err; goto done; } } /* OK, now we have a virtual circuit but no tree connection yet. */ err = smb_share_connect((*outConnection)->context); if (err) { status = STATUS_BAD_NETWORK_NAME; errno = err; goto done; } status = STATUS_SUCCESS; done: if (netfsOptions) { CFRelease(netfsOptions); } if (ServerParams) { CFRelease(ServerParams); } if ((!NT_SUCCESS(status)) && *outConnection) { SMBReleaseServer(*outConnection); *outConnection = NULL; } return status; }
NTSTATUS SMBMountShareEx( SMBHANDLE inConnection, const char *targetShare, const char *mountPoint, unsigned mountFlags, uint64_t mountOptions, mode_t fileMode, mode_t dirMode, void (*callout)(void *, void *), void *args) { NTSTATUS status = STATUS_SUCCESS; int err = 0; void * hContext = NULL; CFStringRef mountPtRef = NULL; CFMutableDictionaryRef mOptions = NULL; CFNumberRef numRef = NULL; status = SMBServerContext(inConnection, &hContext); if (!NT_SUCCESS(status)) { /* Couldn't get the context? */ goto done; } mOptions = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (mOptions == NULL) { /* Couldn't create the mount option dictionary, error out */ errno = ENOMEM; status = STATUS_NO_MEMORY; goto done; } numRef = CFNumberCreate (NULL, kCFNumberSInt32Type, &mountFlags); if (numRef) { /* Put the mount flags into the dictionary */ CFDictionarySetValue (mOptions, kNetFSMountFlagsKey, numRef); CFRelease(numRef); } if (mountOptions & kSMBMntOptionNoStreams) { /* Don't use NTFS Streams even if they are supported by the server. */ CFDictionarySetValue (mOptions, kStreamstMountKey, kCFBooleanFalse); } if (mountOptions & kSMBMntOptionNoNotifcations) { /* Don't use Remote Notifications even if they are supported by the server. */ CFDictionarySetValue (mOptions, kNotifyOffMountKey, kCFBooleanTrue); } if (mountOptions & kSMBMntOptionSoftMount) { /* Mount the volume soft, return time out error durring reconnect. */ CFDictionarySetValue (mOptions, kNetFSSoftMountKey, kCFBooleanTrue); } if (mountOptions & kSMBReservedTMMount) { /* Mount the volume as a Time Machine mount. */ CFDictionarySetValue (mOptions, kTimeMachineMountKey, kCFBooleanTrue); } /* * Specify permissions that should be assigned to files and directories. The * value must be specified as an octal numbers. A value of zero means use the * default values. Not setting these in the dictionary will force the default * values to be used. */ if (fileMode || dirMode) { if (fileMode) { numRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt16Type, &fileMode); if (numRef) { CFDictionarySetValue (mOptions, kfileModeKey, numRef); CFRelease(numRef); } } if (dirMode) { numRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt16Type, &dirMode); if (numRef) { CFDictionarySetValue (mOptions, kdirModeKey, numRef); CFRelease(numRef); } } } /* Get the mount point */ if (mountPoint) { mountPtRef = CFStringCreateWithCString(kCFAllocatorDefault, mountPoint, kCFStringEncodingUTF8); } if (mountPtRef == NULL) { /* No mount point */ errno = ENOMEM; status = STATUS_NO_MEMORY; goto done; } /* Set the share if they gave us one */ if (targetShare) { err = smb_ctx_setshare(hContext, targetShare); } if (err == 0) { err = smb_mount(hContext, mountPtRef, mOptions, NULL, callout, args); } if (err) { errno = err; status = STATUS_UNSUCCESSFUL; goto done; } done: if (mOptions) { CFRelease(mOptions); } if (mountPtRef) { CFRelease(mountPtRef); } return status; }
/* * Here we expect something like "[proto:]//[user@]host[/share][/path]" */ int smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, int sharetype, const char **next) { const char *p = unc; char *p1; char tmp[1024]; int error ; ctx->ct_parsedlevel = SMBL_NONE; if (*p++ != '/' || *p++ != '/') { smb_error("UNC should start with '//'", 0); return EINVAL; } p1 = tmp; error = getsubstring(p, '@', p1, sizeof(tmp), &p); if (!error) { if (ctx->ct_maxlevel < SMBL_VC) { smb_error("no user name required", 0); return EINVAL; } if (*p1 == 0) { smb_error("empty user name", 0); return EINVAL; } error = smb_ctx_setuser(ctx, tmp); if (error) return error; ctx->ct_parsedlevel = SMBL_VC; } error = getsubstring(p, '/', p1, sizeof(tmp), &p); if (error) { error = getsubstring(p, '\0', p1, sizeof(tmp), &p); if (error) { smb_error("no server name found", 0); return error; } } if (*p1 == 0) { smb_error("empty server name", 0); return EINVAL; } error = smb_ctx_setserver(ctx, tmp); if (error) return error; if (sharetype == SMB_ST_NONE) { *next = p; return 0; } if (*p != 0 && ctx->ct_maxlevel < SMBL_SHARE) { smb_error("no share name required", 0); return EINVAL; } error = getsubstring(p, '/', p1, sizeof(tmp), &p); if (error) { error = getsubstring(p, '\0', p1, sizeof(tmp), &p); if (error) { smb_error("unexpected end of line", 0); return error; } } if (*p1 == 0 && ctx->ct_minlevel >= SMBL_SHARE) { smb_error("empty share name", 0); return EINVAL; } *next = p; if (*p1 == 0) return 0; error = smb_ctx_setshare(ctx, p1, sharetype); return error; }
/* * Setup a new SMB client context. * * Get the SMB server's configuration stuff and * store it in the new client context object. */ int smbrdr_ctx_new(struct smb_ctx **ctx_p, char *server, char *domain, char *user) { struct smb_ctx *ctx = NULL; uchar_t nthash[SMBAUTH_HASH_SZ]; int64_t lmcl; int authflags, err; assert(server != NULL); assert(domain != NULL); assert(user != NULL); if ((err = smb_ctx_alloc(&ctx)) != 0) return (NT_STATUS_NO_MEMORY); /* * Set server, share, domain, user * (in the ctx handle). */ (void) smb_ctx_setfullserver(ctx, server); (void) smb_ctx_setshare(ctx, "IPC$", USE_IPC); (void) smb_ctx_setdomain(ctx, domain, B_TRUE); (void) smb_ctx_setuser(ctx, user, B_TRUE); /* * Set auth. info (hash) and type. */ if (user[0] == '\0') { authflags = SMB_AT_ANON; } else { (void) smb_config_getnum(SMB_CI_LM_LEVEL, &lmcl); if (lmcl <= 2) { /* Send NTLM */ authflags = SMB_AT_NTLM1; } else { /* Send NTLMv2 */ authflags = SMB_AT_NTLM2; } smb_ipc_get_passwd(nthash, sizeof (nthash)); (void) smb_ctx_setpwhash(ctx, nthash, NULL); } (void) smb_ctx_setauthflags(ctx, authflags); /* * Do lookup, connect, session setup, tree connect. * Or find and reuse a session/tree, if one exists. */ if ((err = smb_ctx_resolve(ctx)) != 0) { err = NT_STATUS_BAD_NETWORK_PATH; goto errout; } if ((err = smb_ctx_get_ssn(ctx)) != 0) { err = NT_STATUS_NETWORK_ACCESS_DENIED; goto errout; } if ((err = smb_ctx_get_tree(ctx)) != 0) { err = NT_STATUS_BAD_NETWORK_NAME; goto errout; } /* Success! */ *ctx_p = ctx; return (0); errout: smb_ctx_free(ctx); return (err); }
int cmd_view(int argc, char *argv[]) { struct smb_ctx *ctx; int error, err2, opt; if (argc < 2) view_usage(); error = smb_ctx_alloc(&ctx); if (error) return (error); error = smb_ctx_scan_argv(ctx, argc, argv, SMBL_SERVER, SMBL_SERVER, USE_WILDCARD); if (error) return (error); error = smb_ctx_readrc(ctx); if (error) return (error); while ((opt = getopt(argc, argv, STDPARAM_OPT)) != EOF) { if (opt == '?') view_usage(); error = smb_ctx_opt(ctx, opt, optarg); if (error) return (error); } smb_ctx_setshare(ctx, "IPC$", USE_IPC); /* * Resolve the server address, * setup derived defaults. */ error = smb_ctx_resolve(ctx); if (error) return (error); /* * Have server, share, etc. from above: * smb_ctx_scan_argv, option settings. * Get the session and tree. */ again: error = smb_ctx_get_ssn(ctx); if (error == EAUTH) { err2 = smb_get_authentication(ctx); if (err2 == 0) goto again; } if (error) { smb_error(gettext("//%s: login failed"), error, ctx->ct_fullserver); return (error); } error = smb_ctx_get_tree(ctx); if (error) { smb_error(gettext("//%s/%s: tree connect failed"), error, ctx->ct_fullserver, ctx->ct_origshare); return (error); } /* * Have IPC$ tcon, now list shares. * This prints its own errors. */ error = enum_shares(ctx); if (error) return (error); smb_ctx_free(ctx); return (0); }
/* * Here we expect something like "[proto:]//[user@]host[:psmb[:pnb]][/share][/path]" */ int smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, int sharetype, const char **next) { const char *p = unc; char *p1, *psmb, *pnb; char tmp[1024]; int error ; ctx->ct_parsedlevel = SMBL_NONE; if (*p++ != '/' || *p++ != '/') { smb_error("UNC should start with '//'", 0); return EINVAL; } p1 = tmp; error = getsubstring(p, '@', p1, sizeof(tmp), &p); if (!error) { if (ctx->ct_maxlevel < SMBL_VC) { smb_error("no user name required", 0); return EINVAL; } if (*p1 == 0) { smb_error("empty user name", 0); return EINVAL; } error = smb_ctx_setuser(ctx, tmp); if (error) return error; ctx->ct_parsedlevel = SMBL_VC; } error = getsubstring(p, '/', p1, sizeof(tmp), &p); if (error) { error = getsubstring(p, '\0', p1, sizeof(tmp), &p); if (error) { smb_error("no server name found", 0); return error; } } if (*p1 == 0) { smb_error("empty server name", 0); return EINVAL; } /* * Check for port number specification. */ psmb = strchr(tmp, ':'); if (psmb) { *psmb++ = '\0'; pnb = strchr(psmb, ':'); if (pnb) { *pnb++ = '\0'; error = smb_ctx_setnbport(ctx, atoi(pnb)); if (error) { smb_error("Invalid NetBIOS port number", 0); return error; } } error = smb_ctx_setsmbport(ctx, atoi(psmb)); if (error) { smb_error("Invalid SMB port number", 0); return error; } } error = smb_ctx_setserver(ctx, tmp); if (error) return error; if (sharetype == SMB_ST_NONE) { *next = p; return 0; } if (*p != 0 && ctx->ct_maxlevel < SMBL_SHARE) { smb_error("no share name required", 0); return EINVAL; } error = getsubstring(p, '/', p1, sizeof(tmp), &p); if (error) { error = getsubstring(p, '\0', p1, sizeof(tmp), &p); if (error) { smb_error("unexpected end of line", 0); return error; } } if (*p1 == 0 && ctx->ct_minlevel >= SMBL_SHARE) { smb_error("empty share name", 0); return EINVAL; } *next = p; if (*p1 == 0) return 0; error = smb_ctx_setshare(ctx, p1, sharetype); return error; }