Re: Fixing SMB browsing



On Tue, 2006-02-21 at 03:27 +0000, Nate Nielsen wrote:

> Without this flag if a certain set of credentials fail, then
> libsmbclient tries to do an anonymous logon, which from gnome-vfs's
> point of view unexpected behavior, user confusion and frustration.
> There's also no real simple way to tell (from within gnome-vfs) whether
> this 'helpful' behavior occurred or not, but that's beside the point.
> 
> smb-method tries to do an anonymous login first before prompting the
> user for a password. Obviously we're doing it wrong, if the only way
> anonymous logins work is with SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON
> turned off.

With the flag turned on, all we got during testing is that *every* share
asked for a password first, even those that should have let you in
anonymously and without any kind of prompting.  With the flag turned
off, all kinds of shares appear to work fine --- those that let
anonymous logins never prompt you, and those that require authentication
prompt you just fine.  Maybe I'm just being dumb and empirical, but hey,
it works :)

> We currently use 'guest' as an anonymous login. This fixed problems with
> anonymous logins on non-domain simple password based SMB networks. From
> what I remember NULL user/password strings is what libsmbclient uses for
> it's anonymous login. We may need to do try various anonymous logins
> sequentially as (ie: NULL credentials, followed by 'guest').

Sort of --- libsmbclient uses an empty username and password for
anonymous logins (libsmbclient.c:smbc_server()).

> Note that defaulting to an anonymous login is not a problem. The
> fallback in libsmbclient is the only problem. If a user typed in a
> username then that should be the only credentials used, and the password
> should be rejected when invalid.
> 
> In short, the anonymous login code in smb-method needs to be fixed for
> all the different kinds of windows networks. Simply removing the flag
> will cause user confusion and hard to decipher bug reports.

I'm attaching a mail that Derrell Lipman (libsmbclient maintainer) sent
me.

  Federico
--- Begin Message ---
Federico Mena Quintero <federico ximian com> writes:

> Thanks for the quick reply, Derrell.  I'll be pestering you a lot during
> the following days; hope you don't mind ;)

Sounds like I don't have any choice. :-)  Seriously, though, no problem.
There may be times when I'm not able to answer you right away.  Unlike Jeremy,
I'm not getting paid to work on Samba. :-)

>> Note that the caching functions currently are "global"; i.e. there are not
>> separate caches per libsmbclient context.  Again, for most applications,
>> this doesn't matter -- most applications only have one libsmbclient context
>> -- but a few do, and I hope to correct this in the future.
>
> During our meeting in Boston last week, Jeremy was pretty convinced that
> one can't write a program to browse for workgroups/servers/shares and
> access files, while using only a single long-lived context.  Is this
> incorrect?  Or why does testbrowse2.c use multiple contexts?

testbrowse2.c was written by someone who specifically wanted to test multiple
contexts.  I've never found a need for multiple contexts in a single
application -- at least not while the caching functions aren't per-context
anyway.

I now need to talk to Jeremy to find out why he doesn't think the single
context will work.  All of my SMB networking experience is in smaller networks
(real "workgroups" (non-domain) or single domain) so I suspect the problems
come when dealing with the larger and more complicated networks.

If you browse the network from the top, downward, and you find a workgroup or
domain (hereto forth referred to simply as 'workgroup' since they're really the
same thing) and enumerate it and find servers in that workgroup, you should
now have all of the information you need to request authentication: workgroup
and server.  Next, when you browse into the server, you still have workgroup
and server and now also have the share name.  If your user has provided a
username and password for this tuple, you should be able to re-use it.  If you
don't have it, you need to either query the user for it, or try to intuit a
possible answer from what's already been retrieved from the user.  Your only
problem comes when the user specifically requests access to a share but
doesn't give you the workgroup.  You then might need to intuit it somehow.

> The basic requirement is that the user only gets prompted for
> authentication when absolutely necessary.

Seems like a reasonable goal.

> Can you please correct me if anything in the following is wrong:
>
> 1. You can see all the workgroups in your network without requiring
> authentication by doing ctx->opendir("smb://").  Your auth_fn will be
> called, but it doesn't matter what you return.

Correct.

> 2. You can enumerate all the servers in a workgroup without requiring
> authentication by doing ctx->opendir("smb://SOME_WORKGROUP").  Your
> auth_fn will be called, but it doesn't matter what you return.

Correct.

> 3. Some servers require authentication to enumerate the shares they
> export.  This would be
> ctx->opendir("smb://SOME_WORKGROUP;some.host.com").  Some others don't
> require auth to list the shares they have.  How do I detect this?

Unfortunately, I don't think you can detect this.  I believe it's possible to
configure a W2K share, for example, to use share-level security rather than
user-level security and configure other shares to require user-level security.
IIRC, the share using share-level security will be visible if you browse the
server with an arbitrary username/password while the user-level security
shares will not be.  If you were to provide a username/password that gave
access to the user-level security shares, then you'd see them along with the
share-level security share.  You're almost better requesting that the user
provide a username/password for access to any server, and try that same pair
when they attempt to access a share on that server.

> Should I do this:
>
>   int passes;
>   boolean user_canceled;
>
>   static void my_auth_fn (...)
>   {
>      if (passes++ = 1)

note typo: passes++ == 1

>           return; /* or just stick in my defaults */
>      else
>           prompt_user_for_username_and_password (&user_canceled);
>   }
>
>   passes = 1;
>   user_canceled = FALSE;
>
>   cfile = ctx->opendir (ctx, "smb://SOME_WORKGROUP;some.host.com");
>   if (!cfile && errno = EACCESS) {
>        /* oops, retry. */
>     again:
>        cfile = ctx->opendir (ctx, "smb://SOME_WORKGROUP;some.host.com");
>        if (!cfile && errno = EACCESS) {
>             throw_error_dialog ("you can't go in, dude");
>             if (!user_canceled)
>                  goto again;
>        } else
>             get_on_with_life ();
>   }
>
> (And would I have to do the same for every operation on the context?)

Yes, or something similar, if you want to try defaults first.

>> I do not believe that there should be *any* retries using various
>> "fallback" authentication information.  I believe that if the user provides
>> a username and password, that authentication information, and only that,
>> should be tried.  The only thing that might use some default
>> username/password is browsing for servers and shares.  (Browsing, though,
>> may or may not work completely to the share level with default authinfo,
>> depending on the security imposed by the servers being browsed.)
>
> Is it possible to configure a server so that it will list different sets
> of shares depending on what authentication it gets passed?  For example,
> if I pass it a username/password pair of "unknown/blahblah" it will give
> me shares that anyone can read; but if I pass it
> "real_username/real_pass" it will give me those public shares, *plus*
> some other "secret" shares?

Yes, I believe so.  See above.

> [This is where you go, "this fucking moron knows nothing about Samba" -
> and you would be right :) ]

Hey, I still have oodles more to learn!  We all start out as morons, I
guess. :-)

>> In your example, you're given a workgroup, server and share.  I believe
>> that you should be querying the user for a username/password at that time;
>> not trying to fiddle with defaults to "see if it works".  The only
>> exception might be if you've been given authinfo for that workgroup/server
>> (null share), you could try returning that authinfo on this request.  This
>> is a case where you might override the caching functions to allow searching
>> "up the hierarchy" for a reasonable username/password to use.
>
> I guess I'm asking so many questions because I can't find an example of
> using libsmbclient to browse around with behavior similar to Windows
> (i.e. ask the user for auth only if absolutely necessary).  A non-GUI
> example would be fine --- testbrowse.c asks me all the time, and
> testbrowse2.c only has a stub auth_fn :)

I think you're on the right track with your code snippet, above.  In addition,
have your authentication function first look up the username/password for the
provided workgroup/server/share.  If not found, then try workgroup/server.  If
still not found, then query the user.  Oh, and if you've already tried
workgroup/server, immediately query the user.  You'll have to keep some state
information for your shares to know if you've tried inheriting authinfo from
the server already.  This shouldn't be toooooooo difficult, but it won't be
incredibly trivial either.

Cheers,

Derrell

-- 
democracy n.
  A product so extensively exported that the domestic supply is depleted


--- End Message ---


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]