int smb_ctx_login(struct smb_ctx *ctx) { struct smbioc_ossn *ssn = &ctx->ct_ssn; struct smbioc_oshare *sh = &ctx->ct_sh; int error; if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) { smb_error("smb_ctx_resolve() should be called first", 0); return EINVAL; } if (ctx->ct_fd != -1) { close(ctx->ct_fd); ctx->ct_fd = -1; } error = smb_ctx_gethandle(ctx); if (error) { smb_error("can't get handle to requester", 0); return EINVAL; } if (ioctl(ctx->ct_fd, SMBIOC_OPENSESSION, ssn) == -1) { error = errno; smb_error("can't open session to server %s", error, ssn->ioc_srvname); return error; } if (sh->ioc_share[0] == 0) return 0; if (ioctl(ctx->ct_fd, SMBIOC_OPENSHARE, sh) == -1) { error = errno; smb_error("can't connect to share //%s/%s", error, ssn->ioc_srvname, sh->ioc_share); return error; } return 0; }
int smb_ctx_setcharset(struct smb_ctx *ctx, const char *arg) { char *cp, *servercs, *localcs; int cslen = sizeof(ctx->ct_ssn.ioc_localcs); int scslen, lcslen, error; cp = strchr(arg, ':'); lcslen = cp ? (cp - arg) : 0; if (lcslen == 0 || lcslen >= cslen) { smb_error("invalid local charset specification (%s)", 0, arg); return EINVAL; } scslen = (size_t)strlen(++cp); if (scslen == 0 || scslen >= cslen) { smb_error("invalid server charset specification (%s)", 0, arg); return EINVAL; } localcs = memcpy(ctx->ct_ssn.ioc_localcs, arg, lcslen); localcs[lcslen] = 0; servercs = strcpy(ctx->ct_ssn.ioc_servercs, cp); error = nls_setrecode(localcs, servercs); if (error == 0) return 0; smb_error("can't initialize iconv support (%s:%s)", error, localcs, servercs); localcs[0] = 0; servercs[0] = 0; return error; }
int smb_ctx_lookup(struct smb_ctx *ctx, int level, int flags) { struct smbioc_lookup rq; int error; if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) { smb_error("smb_ctx_lookup() data is not resolved", 0); return EINVAL; } if (ctx->ct_fd != -1) { close(ctx->ct_fd); ctx->ct_fd = -1; } error = smb_ctx_gethandle(ctx); if (error) { smb_error("can't get handle to requester (no /dev/"NSMB_NAME"* device)", 0); return EINVAL; } bzero(&rq, sizeof(rq)); bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof(struct smbioc_ossn)); bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof(struct smbioc_oshare)); rq.ioc_flags = flags; rq.ioc_level = level; if (ioctl(ctx->ct_fd, SMBIOC_LOOKUP, &rq) == -1) { error = errno; if (flags & SMBLK_CREATE) smb_error("unable to open connection", error); return error; } return 0; }
static int smb_parse_owner(char *pair, uid_t *uid, gid_t *gid) { struct group *gr; struct passwd *pw; char *cp; cp = strchr(pair, ':'); if (cp) { *cp++ = '\0'; if (*cp) { gr = getgrnam(cp); if (gr) { *gid = gr->gr_gid; } else smb_error("Invalid group name %s, ignored", 0, cp); } } if (*pair) { pw = getpwnam(pair); if (pw) { *uid = pw->pw_uid; } else smb_error("Invalid user name %s, ignored", 0, pair); } endpwent(); return 0; }
int nb_ctx_resolve(struct nb_ctx *ctx) { struct sockaddr *sap; int error; ctx->nb_flags &= ~NBCF_RESOLVED; if (ctx->nb_nsname == NULL) { ctx->nb_ns.sin_addr.s_addr = htonl(INADDR_BROADCAST); } else { error = nb_resolvehost_in(ctx->nb_nsname, &sap); if (error) { smb_error("can't resolve %s", error, ctx->nb_nsname); return error; } if (sap->sa_family != AF_INET) { smb_error("unsupported address family %d", 0, sap->sa_family); free(sap); return EINVAL; } bcopy(sap, &ctx->nb_ns, sizeof(ctx->nb_ns)); free(sap); } ctx->nb_ns.sin_port = htons(137); ctx->nb_ns.sin_family = AF_INET; ctx->nb_ns.sin_len = sizeof(ctx->nb_ns); ctx->nb_flags |= NBCF_RESOLVED; return 0; }
int smb_ctx_setserver(struct smb_ctx *ctx, const char *name) { char *d; /* * If the name contains dot, it's likely a IP address * or a name. Update srvaddr in that case, and use * first part of the name (up to the dot) as NetBIOS name. */ if ((d = strchr(name, '.'))) { static char nm[sizeof(ctx->ct_ssn.ioc_srvname)]; int error; error = smb_ctx_setsrvaddr(ctx, name); if (error) return (error); /* cut name to MAXSRVNAMELEN */ if (strlen(name) >= sizeof(ctx->ct_ssn.ioc_srvname)) { snprintf(nm, sizeof(nm), "%.*s", (int)(sizeof(ctx->ct_ssn.ioc_srvname) - 1), name); name = nm; } } if (strlen(name) >= sizeof(ctx->ct_ssn.ioc_srvname)) { smb_error("server name '%s' too long", 0, name); return ENAMETOOLONG; } nls_str_upper(ctx->ct_ssn.ioc_srvname, name); return 0; }
void smb_rq_wend(struct smb_rq *rqp) { if (rqp->rq_rq.mb_count & 1) smb_error("smbrq_wend: odd word count\n", 0); rqp->rq_wcount = rqp->rq_rq.mb_count / 2; rqp->rq_rq.mb_count = 0; }
static int print_file(smb_ctx_t *ctx, char *title, int file) { off_t offset; int rcnt, wcnt; int setup_len = 0; /* No printer setup data */ int mode = MODE_GRAPHICS; /* treat as raw data */ int error = 0; int pfd = -1; pfd = smb_open_printer(ctx, title, setup_len, mode); if (pfd < 0) { error = errno; smb_error("could not open print job", error); return (error); } offset = 0; for (;;) { rcnt = read(file, databuf, sizeof (databuf)); if (rcnt < 0) { error = errno; smb_error("error reading input file\n", error); break; } if (rcnt == 0) break; wcnt = smb_fh_write(pfd, offset, rcnt, databuf); if (wcnt < 0) { error = errno; smb_error("error writing spool file\n", error); break; } if (wcnt != rcnt) { smb_error("incomplete write to spool file\n", 0); error = EIO; break; } offset += wcnt; } (void) smb_fh_close(pfd); return (error); }
int cmd_lookup(int argc, char *argv[]) { struct nb_ctx *ctx; struct sockaddr *sap; char *hostname; int error, opt; if (argc < 2) lookup_usage(); error = nb_ctx_create(&ctx); if (error) { smb_error("unable to create nbcontext", error); exit(1); } if (smb_open_rcfile() == 0) { if (nb_ctx_readrcsection(smb_rc, ctx, "default", 0) != 0) exit(1); rc_close(smb_rc); } while ((opt = getopt(argc, argv, "w:")) != EOF) { switch(opt) { case 'w': nb_ctx_setns(ctx, optarg); break; default: lookup_usage(); /*NOTREACHED*/ } } if (optind >= argc) lookup_usage(); if (nb_ctx_resolve(ctx) != 0) exit(1); hostname = argv[argc - 1]; /* printf("Looking for %s...\n", hostname);*/ error = nbns_resolvename(hostname, ctx, &sap); if (error) { smb_error("unable to resolve %s", error, hostname); exit(1); } printf("Got response from %s\n", inet_ntoa(ctx->nb_lastns.sin_addr)); printf("IP address of %s: %s\n", hostname, inet_ntoa(((struct sockaddr_in*)sap)->sin_addr)); return 0; }
/* * XXX - NLS, or CF? We should probably use the same routine for all * conversions. */ char * convert_wincs_to_utf8(const char *windows_string) { #ifdef NOTPORTED CFStringRef s; CFIndex maxlen; char *result; s = CFStringCreateWithCString(NULL, windows_string, get_windows_encoding_equivalent()); if (s == NULL) { smb_error("CFStringCreateWithCString for Windows code page failed on \"%s\" ", -1, windows_string); /* kCFStringEncodingMacRoman should always succeed */ s = CFStringCreateWithCString(NULL, windows_string, kCFStringEncodingMacRoman); if (s == NULL) { smb_error("CFStringCreateWithCString for Windows code page failed on \"%s\" with kCFStringEncodingMacRoman - skipping", -1, windows_string); return NULL; } } maxlen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(s), kCFStringEncodingUTF8) + 1; result = malloc(maxlen); if (result == NULL) { smb_error("Couldn't allocate buffer for UTF-8 string for \"%s\" - skipping", -1, windows_string); CFRelease(s); return NULL; } if (!CFStringGetCString(s, result, maxlen, kCFStringEncodingUTF8)) { smb_error("CFStringGetCString for UTF-8 failed on \"%s\" - skipping", -1, windows_string); CFRelease(s); return NULL; } CFRelease(s); return result; #else /* NOTPORTED */ return (strdup((char*)windows_string)); #endif /* NOTPORTED */ }
int smb_ctx_setserver(struct smb_ctx *ctx, const char *name) { if (strlen(name) >= SMB_MAXSRVNAMELEN) { smb_error("server name '%s' too long", 0, name); return ENAMETOOLONG; } nls_str_upper(ctx->ct_ssn.ioc_srvname, name); return 0; }
int smb_ctx_setuser(struct smb_ctx *ctx, const char *name) { if (strlen(name) > SMB_MAXUSERNAMELEN) { smb_error("user name '%s' too long", 0, name); return ENAMETOOLONG; } nls_str_upper(ctx->ct_ssn.ioc_user, name); return 0; }
int smb_ctx_setworkgroup(struct smb_ctx *ctx, const char *name) { if (strlen(name) >= SMB_MAXUSERNAMELEN) { smb_error("workgroup name '%s' too long", 0, name); return ENAMETOOLONG; } nls_str_upper(ctx->ct_ssn.ioc_workgroup, name); return 0; }
static char * convert_ucs2xx_to_utf8(iconv_t cd, const uint16_t *us) { char *obuf, *optr; const char *iptr; size_t ileft, obsize, oleft, ret; if (cd == (iconv_t)-1) { smb_error(dgettext(TEXT_DOMAIN, "iconv_open(UTF-8/UCS-2)"), -1); return (NULL); } iptr = (const char *)us; ileft = unicode_strlen(us); ileft *= 2; /* now bytes */ /* Worst-case output size is 2x input size. */ oleft = ileft * 2; obsize = oleft + 2; /* room for null */ obuf = malloc(obsize); if (!obuf) return (NULL); optr = obuf; ret = iconv(cd, &iptr, &ileft, &optr, &oleft); *optr = '\0'; if (ret == (size_t)-1) { smb_error(dgettext(TEXT_DOMAIN, "iconv(%s) failed"), errno, obuf); } if (ileft) { smb_error(dgettext(TEXT_DOMAIN, "iconv(%s) failed"), -1, obuf); /* * XXX: What's better? return NULL? * The truncated string? << for now */ } return (obuf); }
static uint16_t * convert_utf8_to_ucs2xx(iconv_t cd, const char *utf8_string) { uint16_t *obuf, *optr; const char *iptr; size_t ileft, obsize, oleft, ret; if (cd == (iconv_t)-1) { smb_error(dgettext(TEXT_DOMAIN, "iconv_open(UCS-2/UTF-8)"), -1); return (NULL); } iptr = utf8_string; ileft = strlen(iptr); /* Worst-case output size is 2x input size. */ oleft = ileft * 2; obsize = oleft + 2; /* room for null */ obuf = malloc(obsize); if (!obuf) return (NULL); optr = obuf; ret = iconv(cd, &iptr, &ileft, (char **)&optr, &oleft); *optr = '\0'; if (ret == (size_t)-1) { smb_error(dgettext(TEXT_DOMAIN, "iconv(%s) failed"), errno, utf8_string); } if (ileft) { smb_error(dgettext(TEXT_DOMAIN, "iconv(%s) failed"), -1, utf8_string); /* * XXX: What's better? return NULL? * The truncated string? << for now */ } return (obuf); }
static int smb_addiconvtbl(const char *to, const char *from, const u_char *tbl) { int error; error = kiconv_add_xlat_table(to, from, tbl); if (error && error != EEXIST) { smb_error("can not setup kernel iconv table (%s:%s)", error, from, to); return error; } return 0; }
int smb_ctx_setshare(struct smb_ctx *ctx, const char *share, int stype) { if (strlen(share) >= SMB_MAXSHARENAMELEN) { smb_error("share name '%s' too long", 0, share); return ENAMETOOLONG; } nls_str_upper(ctx->ct_sh.ioc_share, share); if (share[0] != 0) ctx->ct_parsedlevel = SMBL_SHARE; ctx->ct_sh.ioc_stype = stype; return 0; }
/* * level values: * 0 - default * 1 - server * 2 - server:user * 3 - server:user:share */ static int smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level) { char *p; int error; if (level >= 0) { rc_getstringptr(smb_rc, sname, "charsets", &p); if (p) { error = smb_ctx_setcharset(ctx, p); if (error) smb_error("charset specification in the section '%s' ignored", error, sname); } } if (level <= 1) { rc_getint(smb_rc, sname, "timeout", &ctx->ct_ssn.ioc_timeout); rc_getint(smb_rc, sname, "retry_count", &ctx->ct_ssn.ioc_retrycount); } if (level == 1) { rc_getstringptr(smb_rc, sname, "addr", &p); if (p) { error = smb_ctx_setsrvaddr(ctx, p); if (error) { smb_error("invalid address specified in the section %s", 0, sname); return error; } } } if (level >= 2) { rc_getstringptr(smb_rc, sname, "password", &p); if (p) smb_ctx_setpassword(ctx, p); } rc_getstringptr(smb_rc, sname, "workgroup", &p); if (p) smb_ctx_setworkgroup(ctx, p); return 0; }
int smb_ctx_setpassword(struct smb_ctx *ctx, const char *passwd) { if (passwd == NULL) return EINVAL; if (strlen(passwd) >= SMB_MAXPASSWORDLEN) { smb_error("password too long", 0); return ENAMETOOLONG; } if (strncmp(passwd, "$$1", 3) == 0) smb_simpledecrypt(ctx->ct_ssn.ioc_password, passwd); else strcpy(ctx->ct_ssn.ioc_password, passwd); strcpy(ctx->ct_sh.ioc_password, ctx->ct_ssn.ioc_password); return 0; }
int nb_ctx_setscope(struct nb_ctx *ctx, const char *scope) { size_t slen = strlen(scope); if (slen >= 128) { smb_error("scope '%s' is too long", 0, scope); return ENAMETOOLONG; } if (ctx->nb_scope) free(ctx->nb_scope); ctx->nb_scope = malloc(slen + 1); if (ctx->nb_scope == NULL) return ENOMEM; nls_str_upper(ctx->nb_scope, scope); return 0; }
int enum_shares(smb_ctx_t *ctx) { struct share_info *share_info; int error, entries, total; /* * XXX: Later, try RPC first, * then fall back to RAP... */ error = smb_netshareenum(ctx, &entries, &total, &share_info); if (error) { smb_error(gettext("unable to list resources"), error); return (error); } print_shares(entries, total, share_info); return (0); }
static void smb_directory(int dir, struct string *prefix, struct uri *uri) { struct string buf; struct directory_entry *entries; if (!is_in_state(init_directory_listing(&buf, uri), S_OK)) { smb_error(connection_state(S_OUT_OF_MEM)); } fputs("text/html", header_out); fclose(header_out); entries = get_smb_directory_entries(dir, prefix); add_smb_dir_entries(entries, NULL, &buf); add_to_string(&buf, "</pre><hr/></body></html>\n"); fputs(buf.source, data_out); done_string(&buf); exit(0); }
/* * used level values: * 0 - default * 1 - server */ int nb_ctx_readrcsection(struct rcfile *rcfile, struct nb_ctx *ctx, const char *sname, int level) { char *p; int error; if (level > 1) return EINVAL; rc_getint(rcfile, sname, "nbtimeout", &ctx->nb_timo); rc_getstringptr(rcfile, sname, "nbns", &p); if (p) { error = nb_ctx_setns(ctx, p); if (error) { smb_error("invalid address specified in the section %s", 0, sname); return error; } } rc_getstringptr(rcfile, sname, "nbscope", &p); if (p) nb_ctx_setscope(ctx, p); return 0; }
static void do_smb(struct connection *conn) { struct uri *uri = conn->uri; struct auth_entry *auth = find_auth(uri); struct string string; unsigned char *url; int dir; if ((uri->userlen && uri->passwordlen) || !auth) { url = get_uri_string(uri, URI_BASE); } else { unsigned char *uri_string = get_uri_string(uri, URI_HOST | URI_PORT | URI_DATA); if (!uri_string || !init_string(&string)) { smb_error(connection_state(S_OUT_OF_MEM)); } /* Must URI-encode the username and password to avoid * ambiguity if they contain "/:@" characters. * Libsmbclient then decodes them again, and the * server gets them as they were in auth->user and * auth->password, i.e. as the user typed them in the * auth dialog. This implies that, if the username or * password contains some characters or bytes that the * user cannot directly type, then she cannot enter * them. If that becomes an actual problem, it should * be fixed in the auth dialog, e.g. by providing a * hexadecimal input mode. */ add_to_string(&string, "smb://"); encode_uri_string(&string, auth->user, -1, 1); add_char_to_string(&string, ':'); encode_uri_string(&string, auth->password, -1, 1); add_char_to_string(&string, '@'); add_to_string(&string, uri_string); url = string.source; } if (!url) { smb_error(connection_state(S_OUT_OF_MEM)); } if (smbc_init(smb_auth, 0)) { smb_error(connection_state_for_errno(errno)); }; dir = smbc_opendir(url); if (dir >= 0) { struct string prefix; init_string(&prefix); add_to_string(&prefix, url); add_char_to_string(&prefix, '/'); smb_directory(dir, &prefix, conn->uri); done_string(&prefix); } else { const int errno_from_opendir = errno; char buf[READ_SIZE]; struct stat sb; int r, res, fdout; int file = smbc_open(url, O_RDONLY, 0); if (file < 0) { /* If we're opening the list of shares without * proper authentication, then smbc_opendir * fails with EACCES and smbc_open fails with * ENOENT. In this case, return the EACCES so * that the parent ELinks process will prompt * for credentials. */ if (errno == ENOENT && errno_from_opendir == EACCES) errno = errno_from_opendir; smb_error(connection_state_for_errno(errno)); } res = smbc_fstat(file, &sb); if (res) { smb_error(connection_state_for_errno(res)); } /* filesize */ fprintf(header_out, "%" OFF_PRINT_FORMAT, (off_print_T) sb.st_size); fclose(header_out); fdout = fileno(data_out); while ((r = smbc_read(file, buf, READ_SIZE)) > 0) { if (safe_write(fdout, buf, r) <= 0) break; } smbc_close(file); exit(0); } }
int cmd_discon(int argc, char *argv[]) { struct smb_ctx *ctx; int error, opt; if (argc < 2) discon_usage(); error = smb_ctx_alloc(&ctx); if (error != 0) return (error); error = smb_ctx_scan_argv(ctx, argc, argv, SMBL_SERVER, SMBL_SERVER, USE_WILDCARD); if (error != 0) goto out; error = smb_ctx_readrc(ctx); if (error != 0) goto out; while ((opt = getopt(argc, argv, STDPARAM_OPT)) != EOF) { if (opt == '?') discon_usage(); error = smb_ctx_opt(ctx, opt, optarg); if (error != 0) goto out; } /* * Resolve the server address, * setup derived defaults. */ error = smb_ctx_resolve(ctx); if (error != 0) goto out; /* * Have server, user, etc. from above: * smb_ctx_scan_argv, option settings. * * Lookup a session without creating. * (First part of smb_ctx_get_ssn) * If we find the session, kill it. */ error = smb_ctx_findvc(ctx); if (error == ENOENT) { /* Already gone. We're done. */ if (smb_debug) fprintf(stderr, "session not found\n"); error = 0; goto out; } if (error == 0) { /* Found session. Kill it. */ error = smb_ctx_kill(ctx); } if (error != 0) { smb_error(gettext("//%s: discon failed"), error, ctx->ct_fullserver); } out: smb_ctx_free(ctx); return (error); }
static int rpc_netshareenum(struct smb_ctx *ctx, int *entriesp, int *totalp, struct share_info **entries_listp) { char ctx_string[2+16+1]; /* enough for 64-bit pointer, in hex */ unsigned_char_p_t binding; unsigned32 binding_status; rpc_binding_handle_t binding_h; int error, i, entries; char *addrstr, *srvnamestr; unsigned short *usrvnamestr; unsigned32 level; SHARE_ENUM_STRUCT share_info; SHARE_INFO_1_CONTAINER share_info_1_container; SHARE_INFO_1 *shares, *share; unsigned32 total_entries; unsigned32 status, free_status; struct share_info *entry_list, *elp; static EXCEPTION rpc_x_connect_rejected; static int exceptions_initialized; sprintf(ctx_string, "%p", ctx); rpc_string_binding_compose(NULL, "ncacn_np", ctx_string, "srvsvc", NULL, &binding, &binding_status); if (binding_status != rpc_s_ok) { smb_error(dgettext(TEXT_DOMAIN, "rpc_string_binding_compose failed with %d"), 0, binding_status); return (EINVAL); } rpc_binding_from_string_binding(binding, &binding_h, &status); rpc_string_free(&binding, (unsigned32 *)&free_status); if (binding_status != rpc_s_ok) { smb_error(dgettext(TEXT_DOMAIN, "rpc_binding_from_string_binding failed with %d"), 0, binding_status); return (EINVAL); } level = 1; share_info.share_union.level = 1; share_info.share_union.tagged_union.share1 = &share_info_1_container; share_info_1_container.share_count = 0; share_info_1_container.shares = NULL; /* * Convert the server IP address to a string, and send that as * the "server name" - that's what Windows appears to do, and * that avoids problems with NetBIOS names containing * non-ASCII characters. */ addrstr = inet_ntoa(ctx->ct_srvinaddr.sin_addr); srvnamestr = malloc(strlen(addrstr) + 3); if (srvnamestr == NULL) { status = errno; smb_error(dgettext(TEXT_DOMAIN, "can't allocate string for server address"), status); rpc_binding_free(&binding_h, &free_status); return (status); } strcpy(srvnamestr, "\\\\"); strcat(srvnamestr, addrstr); usrvnamestr = convert_utf8_to_leunicode(srvnamestr); if (usrvnamestr == NULL) { smb_error(dgettext(TEXT_DOMAIN, "can't convert string for server address to Unicode"), 0); rpc_binding_free(&binding_h, &free_status); free(srvnamestr); return (EINVAL); } if (!exceptions_initialized) { EXCEPTION_INIT(rpc_x_connect_rejected); exc_set_status(&rpc_x_connect_rejected, rpc_s_connect_rejected); exceptions_initialized = 1; } /* printf("Calling NetrShareEnum.."); XXX */ TRY status = NetrShareEnum(binding_h, usrvnamestr, &level, &share_info, 4294967295U, &total_entries, NULL); if (status != 0) smb_error(dgettext(TEXT_DOMAIN, "error from NetrShareEnum call: status = 0x%08x"), 0, status); /*CSTYLED*/ CATCH (rpc_x_connect_rejected) /* * This is what we get if we can't open the pipe. * That's a normal occurrence when we're talking * to a system that (presumably) doesn't support * DCE RPC on the server side, such as Windows 95/98/Me, * so we don't log an error. */ /*CSTYLED*/ status = ENOTSUP; CATCH_ALL /* * XXX - should we handle some exceptions differently, * returning different errors, and try RAP only for * ENOTSUP? */ smb_error(dgettext(TEXT_DOMAIN, "error from NetrShareEnum call: exception = %u"), 0, THIS_CATCH->match.value); status = ENOTSUP; ENDTRY rpc_binding_free(&binding_h, &free_status); free(srvnamestr); free(usrvnamestr); if (status != 0) return (ENOTSUP); /* * XXX - if the IDL is correct, it's not clear whether the * unmarshalling code will properly handle the case where * a packet where "share_count" and the max count for the * array of shares don't match; a valid DCE RPC implementation * won't marshal something like that, but there's no guarantee * that the server we're talking to has a valid implementation * (which could be a *malicious* implementation!). */ entries = share_info.share_union.tagged_union.share1->share_count; shares = share_info.share_union.tagged_union.share1->shares; entry_list = calloc(entries, sizeof (struct share_info)); if (entry_list == NULL) { error = errno; goto cleanup_and_return; } for (share = shares, elp = entry_list, i = 0; i < entries; i++, share++) { elp->type = share->shi1_type; elp->netname = convert_unicode_to_utf8(share->shi1_share); if (elp->netname == NULL) goto fail; elp->remark = convert_unicode_to_utf8(share->shi1_remark); if (elp->remark == NULL) goto fail; elp++; } *entriesp = entries; *totalp = total_entries; *entries_listp = entry_list; error = 0; goto cleanup_and_return; fail: error = errno; for (elp = entry_list, i = 0; i < entries; i++, elp++) { /* * elp->netname is set before elp->remark, so if * elp->netname is null, elp->remark is also null. * If either of them is null, we haven't done anything * to any entries after this one. */ if (elp->netname == NULL) break; free(elp->netname); if (elp->remark == NULL) break; free(elp->remark); } free(entry_list); cleanup_and_return: for (share = shares, i = 0; i < entries; i++, share++) { free(share->shi1_share); free(share->shi1_remark); } free(shares); /* * XXX - "share1" should be a unique pointer, but we haven't * changed the marshalling code to support non-full pointers * in unions, so we leave it as a full pointer. * * That means that this might, or might not, be changed from * pointing to "share_info_1_container" to pointing to a * mallocated structure, according to the DCE RPC 1.1 IDL spec; * we free it only if it's changed. */ if (share_info.share_union.tagged_union.share1 != &share_info_1_container) free(share_info.share_union.tagged_union.share1); return (error); }
int smb_rap_request(struct smb_rap *rap, struct smb_ctx *ctx) { u_int16_t *rp, conv; u_int32_t *p32; char *dp, *p = rap->r_nparam; char ptype; int error, rdatacnt, rparamcnt, entries, done, dlen; rdatacnt = rap->r_rcvbuflen; rparamcnt = rap->r_plen; error = smb_t2_request(ctx, 0, 0, "\\PIPE\\LANMAN", rap->r_plen, rap->r_pbuf, /* int tparamcnt, void *tparam */ 0, NULL, /* int tdatacnt, void *tdata */ &rparamcnt, rap->r_pbuf, /* rparamcnt, void *rparam */ &rdatacnt, rap->r_rcvbuf /* int *rdatacnt, void *rdata */ ); if (error) return error; rp = (u_int16_t*)rap->r_pbuf; rap->r_result = le16toh(*rp++); conv = le16toh(*rp++); rap->r_npbuf = (char*)rp; rap->r_entries = entries = 0; done = 0; while (!done && *p) { ptype = *p; switch (ptype) { case 'e': rap->r_entries = entries = le16toh(*(u_int16_t*)rap->r_npbuf); rap->r_npbuf += 2; p++; break; default: done = 1; } /* error = smb_rap_parserpparam(p, &p, &plen); if (error) { smb_error("reply parameter mismath %s", 0, p); return EBADRPC; }*/ } rap->r_nparam = p; /* * In general, unpacking entries we may need to relocate * entries for proper alingning. For now use them as is. */ dp = rap->r_rcvbuf; while (entries--) { p = rap->r_sdata; while (*p) { ptype = *p; error = smb_rap_parserpdata(p, &p, &dlen); if (error) { smb_error("reply data mismath %s", 0, p); return EBADRPC; } switch (ptype) { case 'z': p32 = (u_int32_t*)dp; *p32 = (*p32 & 0xffff) - conv; break; } dp += dlen; } } return error; }
int main(int argc, char *argv[]) { struct iovec *iov; unsigned int iovlen; struct smb_ctx sctx, *ctx = &sctx; struct stat st; #ifdef APPLE extern void dropsuid(); extern int loadsmbvfs(); #else struct xvfsconf vfc; #endif char *next, *p, *val; int opt, error, mntflags, caseopt, fd; uid_t uid; gid_t gid; mode_t dir_mode, file_mode; char errmsg[255] = { 0 }; iov = NULL; iovlen = 0; fd = 0; uid = (uid_t)-1; gid = (gid_t)-1; caseopt = 0; file_mode = 0; dir_mode = 0; #ifdef APPLE dropsuid(); #endif if (argc == 2) { if (strcmp(argv[1], "-h") == 0) { usage(); } } if (argc < 3) usage(); #ifdef APPLE error = loadsmbvfs(); #else error = getvfsbyname(smbfs_vfsname, &vfc); if (error) { if (kldload(smbfs_vfsname) < 0) err(EX_OSERR, "kldload(%s)", smbfs_vfsname); error = getvfsbyname(smbfs_vfsname, &vfc); } #endif if (error) errx(EX_OSERR, "SMB filesystem is not available"); if (smb_lib_init() != 0) exit(1); mntflags = error = 0; caseopt = SMB_CS_NONE; if (smb_ctx_init(ctx, argc, argv, SMBL_SHARE, SMBL_SHARE, SMB_ST_DISK) != 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"c:d:f:g:l:n:o:u:w:")) != -1) { switch (opt) { case STDPARAM_ARGS: error = smb_ctx_opt(ctx, opt, optarg); if (error) exit(1); break; case 'u': { struct passwd *pwd; pwd = isdigit(optarg[0]) ? getpwuid(atoi(optarg)) : getpwnam(optarg); if (pwd == NULL) errx(EX_NOUSER, "unknown user '%s'", optarg); uid = pwd->pw_uid; break; } case 'g': { struct group *grp; grp = isdigit(optarg[0]) ? getgrgid(atoi(optarg)) : getgrnam(optarg); if (grp == NULL) errx(EX_NOUSER, "unknown group '%s'", optarg); gid = grp->gr_gid; break; } case 'd': errno = 0; dir_mode = strtol(optarg, &next, 8); if (errno || *next != 0) errx(EX_DATAERR, "invalid value for directory mode"); break; case 'f': errno = 0; file_mode = strtol(optarg, &next, 8); if (errno || *next != 0) errx(EX_DATAERR, "invalid value for file mode"); break; case '?': usage(); /*NOTREACHED*/ case 'n': { char *inp, *nsp; nsp = inp = optarg; while ((nsp = strsep(&inp, ",;:")) != NULL) { if (strcasecmp(nsp, "LONG") == 0) { build_iovec(&iov, &iovlen, "nolong", NULL, 0); } else { errx(EX_DATAERR, "unknown suboption '%s'", nsp); } } break; }; case 'o': getmntopts(optarg, mopts, &mntflags, 0); p = strchr(optarg, '='); val = NULL; if (p != NULL) { *p = '\0'; val = p + 1; } build_iovec(&iov, &iovlen, optarg, val, (size_t)-1); break; case 'c': switch (optarg[0]) { case 'l': caseopt |= SMB_CS_LOWER; break; case 'u': caseopt |= SMB_CS_UPPER; break; default: errx(EX_DATAERR, "invalid suboption '%c' for -c", optarg[0]); } break; default: usage(); } } if (optind == argc - 2) optind++; if (optind != argc - 1) usage(); realpath(argv[optind], mount_point); if (stat(mount_point, &st) == -1) err(EX_OSERR, "could not find mount point %s", mount_point); if (!S_ISDIR(st.st_mode)) { errno = ENOTDIR; err(EX_OSERR, "can't mount on %s", mount_point); } /* if (smb_getextattr(mount_point, &einfo) == 0) errx(EX_OSERR, "can't mount on %s twice", mount_point); */ if (uid == (uid_t)-1) uid = st.st_uid; if (gid == (gid_t)-1) gid = st.st_gid; if (file_mode == 0 ) file_mode = st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); if (dir_mode == 0) { dir_mode = file_mode; if (dir_mode & S_IRUSR) dir_mode |= S_IXUSR; if (dir_mode & S_IRGRP) dir_mode |= S_IXGRP; if (dir_mode & S_IROTH) dir_mode |= S_IXOTH; } /* * For now, let connection be private for this mount */ ctx->ct_ssn.ioc_opt |= SMBVOPT_PRIVATE; ctx->ct_ssn.ioc_owner = ctx->ct_sh.ioc_owner = 0; /* root */ ctx->ct_ssn.ioc_group = ctx->ct_sh.ioc_group = gid; opt = 0; if (dir_mode & S_IXGRP) opt |= SMBM_EXECGRP; if (dir_mode & S_IXOTH) opt |= SMBM_EXECOTH; ctx->ct_ssn.ioc_rights |= opt; ctx->ct_sh.ioc_rights |= opt; error = smb_ctx_resolve(ctx); if (error) exit(1); error = smb_ctx_lookup(ctx, SMBL_SHARE, SMBLK_CREATE); if (error) { exit(1); } fd = ctx->ct_fd; build_iovec(&iov, &iovlen, "fstype", strdup("smbfs"), -1); build_iovec(&iov, &iovlen, "fspath", mount_point, -1); build_iovec_argf(&iov, &iovlen, "fd", "%d", fd); build_iovec(&iov, &iovlen, "mountpoint", mount_point, -1); build_iovec_argf(&iov, &iovlen, "uid", "%d", uid); build_iovec_argf(&iov, &iovlen, "gid", "%d", gid); build_iovec_argf(&iov, &iovlen, "file_mode", "%d", file_mode); build_iovec_argf(&iov, &iovlen, "dir_mode", "%d", dir_mode); build_iovec_argf(&iov, &iovlen, "caseopt", "%d", caseopt); build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof errmsg); error = nmount(iov, iovlen, mntflags); smb_ctx_done(ctx); if (error) { smb_error("mount error: %s %s", error, mount_point, errmsg); exit(1); } return 0; }
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; }
/* * Verify context before connect operation(s), * lookup specified server and try to fill all forgotten fields. */ int smb_ctx_resolve(struct smb_ctx *ctx) { struct smbioc_ossn *ssn = &ctx->ct_ssn; struct smbioc_oshare *sh = &ctx->ct_sh; struct nb_name nn; struct sockaddr *sap; struct sockaddr_nb *salocal, *saserver; char *cp; u_char cstbl[256]; u_int i; int error = 0; ctx->ct_flags &= ~SMBCF_RESOLVED; if (ssn->ioc_srvname[0] == 0) { smb_error("no server name specified", 0); return EINVAL; } if (ssn->ioc_user[0] == 0) { smb_error("no user name specified for server %s", 0, ssn->ioc_srvname); return EINVAL; } if (ctx->ct_minlevel >= SMBL_SHARE && sh->ioc_share[0] == 0) { smb_error("no share name specified for %s@%s", 0, ssn->ioc_user, ssn->ioc_srvname); return EINVAL; } error = nb_ctx_resolve(ctx->ct_nb); if (error) return error; if (ssn->ioc_localcs[0] == 0) strcpy(ssn->ioc_localcs, "default"); /* XXX: locale name ? */ error = smb_addiconvtbl("tolower", ssn->ioc_localcs, nls_lower); if (error) return error; error = smb_addiconvtbl("toupper", ssn->ioc_localcs, nls_upper); if (error) return error; if (ssn->ioc_servercs[0] != 0) { for(i = 0; i < sizeof(cstbl); i++) cstbl[i] = i; nls_mem_toext(cstbl, cstbl, sizeof(cstbl)); error = smb_addiconvtbl(ssn->ioc_servercs, ssn->ioc_localcs, cstbl); if (error) return error; for(i = 0; i < sizeof(cstbl); i++) cstbl[i] = i; nls_mem_toloc(cstbl, cstbl, sizeof(cstbl)); error = smb_addiconvtbl(ssn->ioc_localcs, ssn->ioc_servercs, cstbl); if (error) return error; } if (ctx->ct_srvaddr) { error = nb_resolvehost_in(ctx->ct_srvaddr, &sap); } else { error = nbns_resolvename(ssn->ioc_srvname, ctx->ct_nb, &sap); } if (error) { smb_error("can't get server address", error); return error; } nn.nn_scope = ctx->ct_nb->nb_scope; nn.nn_type = NBT_SERVER; strcpy(nn.nn_name, ssn->ioc_srvname); error = nb_sockaddr(sap, &nn, &saserver); nb_snbfree(sap); if (error) { smb_error("can't allocate server address", error); return error; } ssn->ioc_server = (struct sockaddr*)saserver; if (ctx->ct_locname[0] == 0) { error = nb_getlocalname(ctx->ct_locname); if (error) { smb_error("can't get local name", error); return error; } nls_str_upper(ctx->ct_locname, ctx->ct_locname); } strcpy(nn.nn_name, ctx->ct_locname); nn.nn_type = NBT_WKSTA; nn.nn_scope = ctx->ct_nb->nb_scope; error = nb_sockaddr(NULL, &nn, &salocal); if (error) { nb_snbfree((struct sockaddr*)saserver); smb_error("can't allocate local address", error); return error; } ssn->ioc_local = (struct sockaddr*)salocal; ssn->ioc_lolen = salocal->snb_len; ssn->ioc_svlen = saserver->snb_len; if (ssn->ioc_password[0] == 0 && (ctx->ct_flags & SMBCF_NOPWD) == 0) { cp = getpass("Password:"); error = smb_ctx_setpassword(ctx, cp); if (error) return error; } ctx->ct_flags |= SMBCF_RESOLVED; return 0; }