libsmbclient, authentication during workgroup browsing

Eugene Zagidullin e.asphyx at gmail.com
Wed May 30 05:36:04 MDT 2012


I'm developing simple tool for network browsing using libsmbclient.
Every time I call smbc_getFunctionOpendir(ctx)(ctx, path) with path
looking like "smb://WORKGROUP" auth callback is called. How to get
workgroup members list anonymously and avoid auth callback invocation?
For example on the same machine Nautilus doesn't ask me for
credentials when I'm browsing any workgroup. It asks me only when I
browse machines' shares. So I want to get the same behavior.

Code:
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>

#include <libsmbclient.h>

typedef struct _smb_browser_t smb_browser_t;
struct _smb_browser_t {
	SMBCCTX *ctx;
	bool top_level;

	char *domain;
	char *username;
	char *password;
};

static const char *dirent_type(int type) {
	static const char *types[] = {
		[SMBC_WORKGROUP]		= "WORKGROUP",
		[SMBC_SERVER]			= "SERVER",
		[SMBC_FILE_SHARE]		= "FILE_SHARE",
		[SMBC_PRINTER_SHARE]	= "PRINTER_SHARE",
		[SMBC_COMMS_SHARE]		= "COMMS_SHARE",
		[SMBC_IPC_SHARE]		= "IPC_SHARE",
		[SMBC_DIR]				= "DIR",
		[SMBC_FILE]				= "FILE",
		[SMBC_LINK]				= "LINK",
	};

	return type <= SMBC_LINK ? types[type] : NULL;
}

static void stripln(char *str) {
	int l = strlen(str);
	if(l) {
		while(str[--l] == '\n');
		str[l + 1] = '\0';
	}
}

static void auth_fn(SMBCCTX *ctx,
	const char *server, const char *share,
	char *workgroup, int wgmaxlen, char *username, int unmaxlen,
	char *password, int pwmaxlen) {

	/* Don't authenticate workgroups listing */
    if(!server || !server[0]) return;

	smb_browser_t *browser = (smb_browser_t*)smbc_getOptionUserData(ctx);
	if(browser->top_level) return;

	printf("Server: %s\nShare: %s\n", server, share);

	char buf[256];

	printf("Workgroup [%s]: ", workgroup);
	fgets(buf, sizeof(buf), stdin);
	stripln(buf);
	if(buf[0]) strncpy(workgroup, buf, wgmaxlen);

	printf("Username [%s]: ", username);
	fgets(buf, sizeof(buf), stdin);
	stripln(buf);
	if(buf[0]) strncpy(username, buf, unmaxlen);

	printf("Password [%s]: ", password);
	fgets(buf, sizeof(buf), stdin);
	stripln(buf);
	if(buf[0]) strncpy(password, buf, pwmaxlen);
}

static int browse_dir(smb_browser_t *browser, const char *path) {
	browser->top_level = (strcmp(path, "smb://") == 0);

    SMBCFILE *fp = smbc_getFunctionOpendir(browser->ctx)(browser->ctx, path);
    if(fp == NULL) return -1;

	printf("Directory contents:\n");
	smbc_getdents_fn smbc_getdents = smbc_getFunctionGetdents(browser->ctx);
	char dirbuf[4096];
	int err;
	while((err = smbc_getdents(browser->ctx, fp, (struct
smbc_dirent*)dirbuf, sizeof(dirbuf))) > 0) {
		struct smbc_dirent *dirp = (struct smbc_dirent*)dirbuf;

		while(err > 0) {
			unsigned int dirlen = dirp->dirlen;
			printf("Type: %s, Name: %s, Comment: %s\n",
dirent_type(dirp->smbc_type), dirp->name, dirp->comment);

			dirp = (struct smbc_dirent*)((char*)dirp + dirlen);
			err -= dirlen;
		}
	}
	if(err < 0) return -1;
	smbc_getFunctionClosedir(browser->ctx)(browser->ctx, fp);

	return 0;
}

int main(int argc, char **argv) {
	int ret = 0;

	smb_browser_t *browser = calloc(1, sizeof(smb_browser_t));

    if((browser->ctx = smbc_new_context()) == NULL) {
		ret = 1;
		goto out0;
	}

	smbc_setDebug(browser->ctx, 0);
	smbc_setFunctionAuthDataWithContext(browser->ctx, auth_fn);
	smbc_setOptionUseKerberos(browser->ctx, 1);
	smbc_setOptionFallbackAfterKerberos(browser->ctx, 1);

	smbc_setOptionUserData(browser->ctx, browser);

	if(smbc_init_context(browser->ctx) == NULL) {
		perror("smbc_init_context()");
		ret = 1;
		goto out1;
    }

	const char *path;
	if(argc > 1) {
		path = argv[1];
	} else {
		path = "smb://";
	}

	if(browse_dir(browser, path) < 0) {
		perror(path);
		ret = 1;
		goto out1;
	}

	smbc_getFunctionPurgeCachedServers(browser->ctx)(browser->ctx);

out1:
	smbc_free_context(browser->ctx, 1);

out0:
	free(browser);

	return ret;
}


And it's output:
asphyx at lungo ~/Projects/smbtree $ ./tree smb://GDC
params.c:OpenConfFile() - Unable to open configuration file
"/home/asphyx/.smb/smb.conf":
	No such file or directory
params.c:OpenConfFile() - Unable to open configuration file
"/home/asphyx/.smb/smb.conf.append":
	No such file or directory
Server: GDC
Share: IPC$
Workgroup [MYGROUP]:
Username [asphyx]:
Password []:
Server: AVINO
Share: IPC$
Workgroup [MYGROUP]:
Username [asphyx]:
Password []:
Directory contents:
Type: SERVER, Name: APACSED, Comment:
Type: SERVER, Name: ASAL, Comment:
Type: SERVER, Name: AVINO, Comment:
Type: SERVER, Name: AYAN, Comment:
Type: SERVER, Name: FERRUM, Comment:
Type: SERVER, Name: GB, Comment:
Type: SERVER, Name: PC-YUSHKIN, Comment:
Type: SERVER, Name: PCASHUBIN, Comment:
Type: SERVER, Name: POPOVAL, Comment:
Type: SERVER, Name: SVIN-PC, Comment:
Type: SERVER, Name: X-COL, Comment: Xerox Color printer


More information about the samba-technical mailing list