Exemplo n.º 1
0
static char* passwd2string( const WINBINDD_PW *pw )
{
	static pstring string;
	int ret;
	
	if ( !pw || !pw->pw_name )
		return NULL;
	
	DEBUG(10,("passwd2string: converting passwd struct for %s\n", 
		pw->pw_name));

	ret = pstr_sprintf( string, "%s:%s:%lu:%lu:%s:%s:%s",
		pw->pw_name, 
		pw->pw_passwd ? pw->pw_passwd : "x",
		(unsigned long)pw->pw_uid,
		(unsigned long)pw->pw_gid,
		pw->pw_gecos,
		pw->pw_dir,
		pw->pw_shell );
		
	if ( ret < 0 ) {
		DEBUG(0,("passwd2string: pstr_sprintf() failed!\n"));
		return NULL;
	}
		
	return string;	
}
Exemplo n.º 2
0
static BOOL make_full_path( pstring path, const char *server, const char *share,
                            const char *dir )
{
	pstring servicename;
	char *sharename;
	const char *directory;

	
	/* make a copy so we don't modify the global string 'service' */
	
	pstrcpy(servicename, share);
	sharename = servicename;
	
	if (*sharename == '\\') {
	
		server = sharename+2;
		sharename = strchr_m(server,'\\');
		
		if (!sharename) 
			return False;
			
		*sharename = 0;
		sharename++;
	}

	directory = dir;
	if ( *directory == '\\' )
		directory++;
	
	pstr_sprintf( path, "\\%s\\%s\\%s", server, sharename, directory );

	return True;
}
Exemplo n.º 3
0
BOOL regdb_store_values( const char *key, REGVAL_CTR *values )
{
	TDB_DATA data;
	pstring keystr;
	int len, ret;
	
	DEBUG(10,("regdb_store_values: Looking for value of key [%s] \n", key));
	
	ZERO_STRUCT( data );
	
	len = regdb_pack_values( values, data.dptr, data.dsize );
	if ( len <= 0 ) {
		DEBUG(0,("regdb_store_values: unable to pack values. len <= 0\n"));
		return False;
	}
	
	data.dptr = SMB_MALLOC_ARRAY( char, len );
	data.dsize = len;
	
	len = regdb_pack_values( values, data.dptr, data.dsize );
	
	SMB_ASSERT( len == data.dsize );
	
	pstr_sprintf( keystr, "%s/%s", VALUE_PREFIX, key );
	normalize_reg_path( keystr );
	
	ret = tdb_store_bystring(tdb_reg, keystr, data, TDB_REPLACE);
	
	SAFE_FREE( data.dptr );
	
	return ret != -1 ;
}
Exemplo n.º 4
0
BOOL cli_check_msdfs_proxy( struct cli_state *cli, const char *sharename,
                            fstring newserver, fstring newshare )
{
	CLIENT_DFS_REFERRAL *refs = NULL;
	size_t num_refs;
	uint16 consumed;
	pstring fullpath;
	BOOL res;
	uint16 cnum;
	pstring newextrapath;
	
	if ( !cli || !sharename )
		return False;

	cnum = cli->cnum;

	/* special case.  never check for a referral on the IPC$ share */

	if ( strequal( sharename, "IPC$" ) ) {
		return False;
	}
		
	/* send a trans2_query_path_info to check for a referral */
	
	pstr_sprintf( fullpath, "\\%s\\%s", cli->desthost, sharename );

	/* check for the referral */

	if (!cli_send_tconX(cli, "IPC$", "IPC", NULL, 0)) {
		return False;
	}

	res = cli_dfs_get_referral(cli, fullpath, &refs, &num_refs, &consumed);

	if (!cli_tdis(cli)) {
		SAFE_FREE( refs );
		return False;
	}

	cli->cnum = cnum;

	if (!res || !num_refs ) {
		SAFE_FREE( refs );
		return False;
	}
	
	split_dfs_path( refs[0].dfspath, newserver, newshare, newextrapath );

	/* check that this is not a self-referral */

	if ( strequal( cli->desthost, newserver ) && strequal( sharename, newshare ) ) {
		SAFE_FREE( refs );
		return False;
	}
	
	SAFE_FREE( refs );
	
	return True;
}
Exemplo n.º 5
0
/**
 * Form a key for fetching a trusted domain password
 *
 * @param domain trusted domain name
 *
 * @return stored password's key
 **/
static char *trustdom_keystr(const char *domain)
{
	static pstring keystr;

	pstr_sprintf(keystr, "%s/%s", SECRETS_DOMTRUST_ACCT_PASS, domain);
	strupper_m(keystr);
		
	return keystr;
}
Exemplo n.º 6
0
static void cli_dfs_make_full_path( struct cli_state *cli,
					const char *dir,
					pstring path_out)
{
	/* Ensure the extrapath doesn't start with a separator. */
	while (IS_DIRECTORY_SEP(*dir)) {
		dir++;
	}

	pstr_sprintf( path_out, "\\%s\\%s\\%s", cli->desthost, cli->share, dir);
}
Exemplo n.º 7
0
static void terminate(void)
{
	pstring path;

	idmap_close();
	
	/* Remove socket file */
	pstr_sprintf(path, "%s/%s", 
		 WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME);
	unlink(path);
	exit(0);
}
Exemplo n.º 8
0
static void set_logfile(poptContext con, const char * arg)
{

	pstring logfile;
	const char *pname;
	
	/* Find out basename of current program */
	pname = strrchr_m(poptGetInvocationName(con),'/');

	if (!pname)
		pname = poptGetInvocationName(con);
	else 
		pname++;

#ifdef EMBED
	pstr_sprintf(logfile, "%s/smb_log.%s", arg, pname);
#else
	pstr_sprintf(logfile, "%s/log.%s", arg, pname);
#endif
	lp_set_logfile(logfile);
}
Exemplo n.º 9
0
static void offer_gss_spnego_mechs(void) {

	DATA_BLOB token;
	SPNEGO_DATA spnego;
	ssize_t len;
	char *reply_base64;

	pstring principal;
	pstring myname_lower;

	ZERO_STRUCT(spnego);

	pstrcpy(myname_lower, global_myname());
	strlower_m(myname_lower);

	pstr_sprintf(principal, "%s$@%s", myname_lower, lp_realm());

	/* Server negTokenInit (mech offerings) */
	spnego.type = SPNEGO_NEG_TOKEN_INIT;
	spnego.negTokenInit.mechTypes = SMB_XMALLOC_ARRAY(const char *, 2);
#ifdef HAVE_KRB5
	spnego.negTokenInit.mechTypes[0] = smb_xstrdup(OID_KERBEROS5_OLD);
	spnego.negTokenInit.mechTypes[1] = smb_xstrdup(OID_NTLMSSP);
	spnego.negTokenInit.mechTypes[2] = NULL;
#else
	spnego.negTokenInit.mechTypes[0] = smb_xstrdup(OID_NTLMSSP);
	spnego.negTokenInit.mechTypes[1] = NULL;
#endif


	spnego.negTokenInit.mechListMIC = data_blob(principal,
						    strlen(principal));

	len = write_spnego_data(&token, &spnego);
	free_spnego_data(&spnego);

	if (len == -1) {
		DEBUG(1, ("Could not write SPNEGO data blob\n"));
		x_fprintf(x_stdout, "BH\n");
		return;
	}

	reply_base64 = base64_encode_data_blob(token);
	x_fprintf(x_stdout, "TT %s *\n", reply_base64);

	SAFE_FREE(reply_base64);
	data_blob_free(&token);
	DEBUG(10, ("sent SPNEGO negTokenInit\n"));
	return;
}
Exemplo n.º 10
0
int regdb_fetch_values( const char* key, REGVAL_CTR *values )
{
	TDB_DATA data;
	pstring keystr;

	DEBUG(10,("regdb_fetch_values: Looking for value of key [%s] \n", key));
	
	pstr_sprintf( keystr, "%s/%s", VALUE_PREFIX, key );
	normalize_reg_path( keystr );
	
	data = tdb_fetch_bystring( tdb_reg, keystr );
	
	if ( !data.dptr ) {
		/* all keys have zero values by default */
		return 0;
	}
	
	regdb_unpack_values( values, data.dptr, data.dsize );
	
	SAFE_FREE( data.dptr );
	
	return regval_ctr_numvals(values);
}
Exemplo n.º 11
0
static void *find_fn(const char *name)
{
	pstring s;
	static void *h;
	void *res;

	pstr_sprintf(s, "_nss_%s_%s", nss_name, name);

	if (!h) {
		h = sys_dlopen(so_path, RTLD_LAZY);
	}
	if (!h) {
		printf("Can't open shared library %s\n", so_path);
		exit(1);
	}
	res = sys_dlsym(h, s);
	if (!res) {
		printf("Can't find function %s\n", s);
		total_errors++;
		return NULL;
	}
	return res;
}
Exemplo n.º 12
0
static int
cups_job_submit(int snum, struct printjob *pjob)
{
	int		ret;		/* Return value */
	http_t		*http;		/* HTTP connection to server */
	ipp_t		*request,	/* IPP Request */
			*response;	/* IPP Response */
	cups_lang_t	*language;	/* Default language */
	char		uri[HTTP_MAX_URI]; /* printer-uri attribute */
	char 		*clientname; 	/* hostname of client for job-originating-host attribute */
	pstring		new_jobname;
	int		num_options = 0; 
	cups_option_t 	*options;

	DEBUG(5,("cups_job_submit(%d, %p (%d))\n", snum, pjob, pjob->sysjob));

       /*
        * Make sure we don't ask for passwords...
	*/

        cupsSetPasswordCB(cups_passwd_cb);

       /*
	* Try to connect to the server...
	*/

	if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
	{
		DEBUG(0,("Unable to connect to CUPS server %s - %s\n", 
			 cupsServer(), strerror(errno)));
		return (1);
	}

       /*
	* Build an IPP_PRINT_JOB request, which requires the following
	* attributes:
	*
	*    attributes-charset
	*    attributes-natural-language
	*    printer-uri
	*    requesting-user-name
	*    [document-data]
	*/

	request = ippNew();

	request->request.op.operation_id = IPP_PRINT_JOB;
	request->request.op.request_id   = 1;

	language = cupsLangDefault();

	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
        	     "attributes-charset", NULL, cupsLangEncoding(language));

	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
        	     "attributes-natural-language", NULL, language->language);

	slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
	         PRINTERNAME(snum));

	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
        	     "printer-uri", NULL, uri);

	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
        	     NULL, pjob->user);

	clientname = client_name();
	if (strcmp(clientname, "UNKNOWN") == 0) {
		clientname = client_addr();
	}

	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
	             "job-originating-host-name", NULL,
		      clientname);

        pstr_sprintf(new_jobname,"%s%.8u %s", PRINT_SPOOL_PREFIX, 
		(unsigned int)pjob->smbjob, pjob->jobname);

	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
        	     new_jobname);

	/* 
	 * add any options defined in smb.conf 
	 */

	num_options = 0;
	options     = NULL;
	num_options = cupsParseOptions(lp_cups_options(snum), num_options, &options);

	if ( num_options )
		cupsEncodeOptions(request, num_options, options); 

       /*
	* Do the request and get back a response...
	*/

	slprintf(uri, sizeof(uri) - 1, "/printers/%s", PRINTERNAME(snum));

        ret = 1;
	if ((response = cupsDoFileRequest(http, request, uri,
	                                  pjob->filename)) != NULL)
	{
		if (response->request.status.status_code >= IPP_OK_CONFLICT)
			DEBUG(0,("Unable to print file to %s - %s\n", PRINTERNAME(snum),
			         ippErrorString(cupsLastError())));
        	else
			ret = 0;

		ippDelete(response);
	}
	else
		DEBUG(0,("Unable to print file to `%s' - %s\n", PRINTERNAME(snum),
			 ippErrorString(cupsLastError())));

	httpClose(http);

	if ( ret == 0 )
		unlink(pjob->filename);
	/* else print_job_end will do it for us */

	return (ret);
}
Exemplo n.º 13
0
BOOL cli_resolve_path( const char *mountpt,
			struct cli_state *rootcli,
			const char *path,
			struct cli_state **targetcli,
			pstring targetpath)
{
	CLIENT_DFS_REFERRAL *refs = NULL;
	size_t num_refs;
	uint16 consumed;
	struct cli_state *cli_ipc;
	pstring dfs_path, cleanpath, extrapath;
	int pathlen;
	fstring server, share;
	struct cli_state *newcli;
	pstring newpath;
	pstring newmount;
	char *ppath, *temppath = NULL;
	
	SMB_STRUCT_STAT sbuf;
	uint32 attributes;
	
	if ( !rootcli || !path || !targetcli ) {
		return False;
	}
		
	/* Don't do anything if this is not a DFS root. */

	if ( !rootcli->dfsroot) {
		*targetcli = rootcli;
		pstrcpy( targetpath, path );
		return True;
	}

	*targetcli = NULL;

	/* Send a trans2_query_path_info to check for a referral. */

	clean_path(path, cleanpath);
	cli_dfs_make_full_path(rootcli, cleanpath, dfs_path );

	if (cli_qpathinfo_basic( rootcli, dfs_path, &sbuf, &attributes ) ) {
		/* This is an ordinary path, just return it. */
		*targetcli = rootcli;
		pstrcpy( targetpath, path );
		goto done;
	}

	/* Special case where client asked for a path that does not exist */

	if ( cli_dfs_check_error(rootcli, NT_STATUS_OBJECT_NAME_NOT_FOUND) ) {
		*targetcli = rootcli;
		pstrcpy( targetpath, path );
		goto done;
	}

	/* We got an error, check for DFS referral. */

	if ( !cli_dfs_check_error(rootcli, NT_STATUS_PATH_NOT_COVERED))  {
		return False;
	}

	/* Check for the referral. */

	if ( !(cli_ipc = cli_cm_open( rootcli->desthost, "IPC$", False )) ) {
		return False;
	}
	
	if ( !cli_dfs_get_referral(cli_ipc, dfs_path, &refs, &num_refs, &consumed) 
			|| !num_refs ) {
		return False;
	}
	
	/* Just store the first referral for now. */

	split_dfs_path( refs[0].dfspath, server, share, extrapath );
	SAFE_FREE(refs);

	/* Make sure to recreate the original string including any wildcards. */
	
	cli_dfs_make_full_path( rootcli, path, dfs_path);
	pathlen = strlen( dfs_path )*2;
	consumed = MIN(pathlen, consumed );
	pstrcpy( targetpath, &dfs_path[consumed/2] );
	dfs_path[consumed/2] = '\0';

	/*
 	 * targetpath is now the unconsumed part of the path.
 	 * dfs_path is now the consumed part of the path (in \server\share\path format).
 	 */

	/* Open the connection to the target server & share */
	
	if ( (*targetcli = cli_cm_open(server, share, False)) == NULL ) {
		d_printf("Unable to follow dfs referral [\\%s\\%s]\n",
			server, share );
		return False;
	}
	
	if (strlen(extrapath) > 0) {
		string_append(&temppath, extrapath);
		string_append(&temppath, targetpath);
		pstrcpy( targetpath, temppath );
	}
	
	/* parse out the consumed mount path */
	/* trim off the \server\share\ */

	ppath = dfs_path;

	if (*ppath != '\\') {
		d_printf("cli_resolve_path: dfs_path (%s) not in correct format.\n",
			dfs_path );
		return False;
	}

	ppath++; /* Now pointing at start of server name. */
	
	if ((ppath = strchr_m( dfs_path, '\\' )) == NULL) {
		return False;
	}

	ppath++; /* Now pointing at start of share name. */

	if ((ppath = strchr_m( ppath+1, '\\' )) == NULL) {
		return False;
	}

	ppath++; /* Now pointing at path component. */

	pstr_sprintf( newmount, "%s\\%s", mountpt, ppath );

	cli_cm_set_mntpoint( *targetcli, newmount );

	/* Check for another dfs referral, note that we are not 
	   checking for loops here. */

	if ( !strequal( targetpath, "\\" ) &&  !strequal( targetpath, "/")) {
		if ( cli_resolve_path( newmount, *targetcli, targetpath, &newcli, newpath ) ) {
			/*
			 * When cli_resolve_path returns true here it's always
 			 * returning the complete path in newpath, so we're done
 			 * here.
 			 */
			*targetcli = newcli;
			pstrcpy( targetpath, newpath );
			return True;
		}
	}

  done:

	/* If returning True ensure we return a dfs root full path. */
	if ( (*targetcli)->dfsroot ) {
		pstrcpy(dfs_path, targetpath );
		cli_dfs_make_full_path( *targetcli, dfs_path, targetpath); 
	}

	return True;
}
Exemplo n.º 14
0
static void popt_common_credentials_callback(poptContext con, 
					enum poptCallbackReason reason,
					const struct poptOption *opt,
					const char *arg, const void *data)
{
	char *p;

	if (reason == POPT_CALLBACK_REASON_PRE) {
		cmdline_auth_info.use_kerberos = False;
		cmdline_auth_info.got_pass = False;
		cmdline_auth_info.signing_state = Undefined;
		pstrcpy(cmdline_auth_info.username, "GUEST");	

		if (getenv("LOGNAME"))pstrcpy(cmdline_auth_info.username,getenv("LOGNAME"));

		if (getenv("USER")) {
			pstrcpy(cmdline_auth_info.username,getenv("USER"));

			if ((p = strchr_m(cmdline_auth_info.username,'%'))) {
				*p = 0;
				pstrcpy(cmdline_auth_info.password,p+1);
				cmdline_auth_info.got_pass = True;
				memset(strchr_m(getenv("USER"),'%')+1,'X',strlen(cmdline_auth_info.password));
			}
		}

		if (getenv("PASSWD")) {
			pstrcpy(cmdline_auth_info.password,getenv("PASSWD"));
			cmdline_auth_info.got_pass = True;
		}

		if (getenv("PASSWD_FD") || getenv("PASSWD_FILE")) {
			get_password_file(&cmdline_auth_info);
			cmdline_auth_info.got_pass = True;
		}

		return;
	}

	switch(opt->val) {
	case 'U':
		{
			char *lp;

			pstrcpy(cmdline_auth_info.username,arg);
			if ((lp=strchr_m(cmdline_auth_info.username,'%'))) {
				*lp = 0;
				pstrcpy(cmdline_auth_info.password,lp+1);
				cmdline_auth_info.got_pass = True;
				memset(strchr_m(arg,'%')+1,'X',strlen(cmdline_auth_info.password));
			}
		}
		break;

	case 'A':
		get_credentials_file(arg, &cmdline_auth_info);
		break;

	case 'k':
#ifndef HAVE_KRB5
		d_printf("No kerberos support compiled in\n");
		exit(1);
#else
		cmdline_auth_info.use_kerberos = True;
		cmdline_auth_info.got_pass = True;
#endif
		break;

	case 'S':
		{
			cmdline_auth_info.signing_state = -1;
			if (strequal(arg, "off") || strequal(arg, "no") || strequal(arg, "false"))
				cmdline_auth_info.signing_state = False;
			else if (strequal(arg, "on") || strequal(arg, "yes") || strequal(arg, "true") ||
					strequal(arg, "auto") )
				cmdline_auth_info.signing_state = True;
			else if (strequal(arg, "force") || strequal(arg, "required") || strequal(arg, "forced"))
				cmdline_auth_info.signing_state = Required;
			else {
				fprintf(stderr, "Unknown signing option %s\n", arg );
				exit(1);
			}
		}
		break;
	case 'P':
	        {
			char *opt_password = NULL;
			/* it is very useful to be able to make ads queries as the
			   machine account for testing purposes and for domain leave */
			
			if (!secrets_init()) {
				d_printf("ERROR: Unable to open secrets database\n");
				exit(1);
			}
			
			opt_password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
			
			if (!opt_password) {
				d_printf("ERROR: Unable to fetch machine password\n");
				exit(1);
			}
			pstr_sprintf(cmdline_auth_info.username, "%s$", 
				     global_myname());
			pstrcpy(cmdline_auth_info.password,opt_password);
			SAFE_FREE(opt_password);

			/* machine accounts only work with kerberos */
			cmdline_auth_info.use_kerberos = True;
			cmdline_auth_info.got_pass = True;
		}
		break;
	}
}
Exemplo n.º 15
0
int create_pipe_sock(const char *socket_dir,
		     const char *socket_name,
		     mode_t dir_perms)
{
#ifdef HAVE_UNIXSOCKET
	struct sockaddr_un sunaddr;
	struct stat st;
	int sock;
	mode_t old_umask;
	pstring path;
        
	old_umask = umask(0);
        
	/* Create the socket directory or reuse the existing one */
        
	if (lstat(socket_dir, &st) == -1) {
		if (errno == ENOENT) {
			/* Create directory */
			if (mkdir(socket_dir, dir_perms) == -1) {
				DEBUG(0, ("error creating socket directory "
					"%s: %s\n", socket_dir, 
					strerror(errno)));
				goto out_umask;
			}
		} else {
			DEBUG(0, ("lstat failed on socket directory %s: %s\n",
				socket_dir, strerror(errno)));
			goto out_umask;
		}
	} else {
		/* Check ownership and permission on existing directory */
		if (!S_ISDIR(st.st_mode)) {
			DEBUG(0, ("socket directory %s isn't a directory\n",
				socket_dir));
			goto out_umask;
		}
		if ((st.st_uid != sec_initial_uid()) || 
				((st.st_mode & 0777) != dir_perms)) {
			DEBUG(0, ("invalid permissions on socket directory "
				"%s\n", socket_dir));
			goto out_umask;
		}
	}
        
	/* Create the socket file */
        
	sock = socket(AF_UNIX, SOCK_STREAM, 0);
        
	if (sock == -1) {
		perror("socket");
                goto out_umask;
	}
        
	pstr_sprintf(path, "%s/%s", socket_dir, socket_name);
        
	unlink(path);
	memset(&sunaddr, 0, sizeof(sunaddr));
	sunaddr.sun_family = AF_UNIX;
	safe_strcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path)-1);
        
	if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1) {
		DEBUG(0, ("bind failed on pipe socket %s: %s\n", path,
			strerror(errno)));
		goto out_close;
	}
        
	if (listen(sock, 5) == -1) {
		DEBUG(0, ("listen failed on pipe socket %s: %s\n", path,
			strerror(errno)));
		goto out_close;
	}
        
	umask(old_umask);
	return sock;

out_close:
	close(sock);

out_umask:
	umask(old_umask);
	return -1;

#else
        DEBUG(0, ("create_pipe_sock: No Unix sockets on this system\n"));
        return -1;
#endif /* HAVE_UNIXSOCKET */
}
Exemplo n.º 16
0
static void popt_common_callback(poptContext con,
			   enum poptCallbackReason reason,
			   const struct poptOption *opt,
			   const char *arg, const void *data)
{

	if (reason == POPT_CALLBACK_REASON_PRE) {
		set_logfile(con, dyn_LOGFILEBASE);
		return;
	}

	switch(opt->val) {
	case 'd':
		if (arg) {
			debug_parse_levels(arg);
			AllowDebugChange = False;
		}
		break;

	case 'V':
		printf( "Version %s\n", SAMBA_VERSION_STRING);
		exit(0);
		break;

	case 'O':
		if (arg) {
			pstrcpy(user_socket_options,arg);
		}
		break;

	case 's':
		if (arg) {
			pstrcpy(dyn_CONFIGFILE, arg);
		}
		break;

	case 'n':
		if (arg) {
			set_global_myname(arg);
		}
		break;

	case 'l':
		if (arg) {
			set_logfile(con, arg);
			override_logfile = True;
			pstr_sprintf(dyn_LOGFILEBASE, "%s", arg);
		}
		break;

	case 'i':
		if (arg) {
			  set_global_scope(arg);
		}
		break;

	case 'W':
		if (arg) {
			set_global_myworkgroup(arg);
		}
		break;
	}
}
Exemplo n.º 17
0
BOOL cli_resolve_path( const char *mountpt, struct cli_state *rootcli, const char *path,
                       struct cli_state **targetcli, pstring targetpath )
{
	CLIENT_DFS_REFERRAL *refs = NULL;
	size_t num_refs;
	uint16 consumed;
	struct cli_state *cli_ipc;
	pstring fullpath, cleanpath;
	int pathlen;
	fstring server, share;
	struct cli_state *newcli;
	pstring newpath;
	pstring newmount;
	char *ppath;
	
	SMB_STRUCT_STAT sbuf;
	uint32 attributes;
	
	*targetcli = NULL;
	
	if ( !rootcli || !path || !targetcli )
		return False;
		
	/* send a trans2_query_path_info to check for a referral */
	
	clean_path( cleanpath, 	path );
	make_full_path( fullpath, rootcli->desthost, rootcli->share, cleanpath );

	/* don't bother continuing if this is not a dfs root */
	
	if ( !rootcli->dfsroot || cli_qpathinfo_basic( rootcli, cleanpath, &sbuf, &attributes ) ) {
		*targetcli = rootcli;
		pstrcpy( targetpath, path );
		return True;
	}

	/* we got an error, check for DFS referral */
			
	if ( !cli_dfs_check_error(rootcli) ) 
		return False;

	/* check for the referral */

	if ( !(cli_ipc = cli_cm_open( rootcli->desthost, "IPC$", False )) )
		return False;
	
	if ( !cli_dfs_get_referral(cli_ipc, fullpath, &refs, &num_refs, &consumed) 
		|| !num_refs )
	{
		return False;
	}
	
	/* just store the first referral for now
	   Make sure to recreate the original string including any wildcards */
	
	make_full_path( fullpath, rootcli->desthost, rootcli->share, path );
	pathlen = strlen( fullpath )*2;
	consumed = MIN(pathlen, consumed );
	pstrcpy( targetpath, &fullpath[consumed/2] );

	split_dfs_path( refs[0].dfspath, server, share );
	SAFE_FREE( refs );
	
	/* open the connection to the target path */
	
	if ( (*targetcli = cli_cm_open(server, share, False)) == NULL ) {
		d_printf("Unable to follow dfs referral [//%s/%s]\n",
			server, share );
			
		return False;
	}
	
	/* parse out the consumed mount path */
	/* trim off the \server\share\ */

	fullpath[consumed/2] = '\0';
	dos_clean_name( fullpath );
	ppath = strchr_m( fullpath, '\\' );
	ppath = strchr_m( ppath+1, '\\' );
	ppath = strchr_m( ppath+1, '\\' );
	ppath++;
	
	pstr_sprintf( newmount, "%s\\%s", mountpt, ppath );
	cli_cm_set_mntpoint( *targetcli, newmount );

	/* check for another dfs referral, note that we are not 
	   checking for loops here */

	if ( !strequal( targetpath, "\\" ) ) {
		if ( cli_resolve_path( newmount, *targetcli, targetpath, &newcli, newpath ) ) {
			*targetcli = newcli;
			pstrcpy( targetpath, newpath );
		}
	}

	return True;
}
Exemplo n.º 18
0
static void manage_gss_spnego_request(enum stdio_helper_mode stdio_helper_mode, 
				      char *buf, int length) 
{
	static NTLMSSP_STATE *ntlmssp_state = NULL;
	SPNEGO_DATA request, response;
	DATA_BLOB token;
	NTSTATUS status;
	ssize_t len;

	char *user = NULL;
	char *domain = NULL;

	const char *reply_code;
	char       *reply_base64;
	pstring     reply_argument;

	if (strlen(buf) < 2) {
		DEBUG(1, ("SPENGO query [%s] invalid", buf));
		x_fprintf(x_stdout, "BH\n");
		return;
	}

	if (strncmp(buf, "YR", 2) == 0) {
		if (ntlmssp_state)
			ntlmssp_end(&ntlmssp_state);
	} else if (strncmp(buf, "KK", 2) == 0) {
		
	} else {
		DEBUG(1, ("SPENGO query [%s] invalid", buf));
		x_fprintf(x_stdout, "BH\n");
		return;
	}

	if ( (strlen(buf) == 2)) {

		/* no client data, get the negTokenInit offering
                   mechanisms */

		offer_gss_spnego_mechs();
		return;
	}

	/* All subsequent requests have a blob. This might be negTokenInit or negTokenTarg */

	if (strlen(buf) <= 3) {
		DEBUG(1, ("GSS-SPNEGO query [%s] invalid\n", buf));
		x_fprintf(x_stdout, "BH\n");
		return;
	}

	token = base64_decode_data_blob(buf + 3);
	len = read_spnego_data(token, &request);
	data_blob_free(&token);

	if (len == -1) {
		DEBUG(1, ("GSS-SPNEGO query [%s] invalid", buf));
		x_fprintf(x_stdout, "BH\n");
		return;
	}

	if (request.type == SPNEGO_NEG_TOKEN_INIT) {

		/* Second request from Client. This is where the
		   client offers its mechanism to use. */

		if ( (request.negTokenInit.mechTypes == NULL) ||
		     (request.negTokenInit.mechTypes[0] == NULL) ) {
			DEBUG(1, ("Client did not offer any mechanism"));
			x_fprintf(x_stdout, "BH\n");
			return;
		}

		status = NT_STATUS_UNSUCCESSFUL;
		if (strcmp(request.negTokenInit.mechTypes[0], OID_NTLMSSP) == 0) {

			if ( request.negTokenInit.mechToken.data == NULL ) {
				DEBUG(1, ("Client did not provide  NTLMSSP data\n"));
				x_fprintf(x_stdout, "BH\n");
				return;
			}

			if ( ntlmssp_state != NULL ) {
				DEBUG(1, ("Client wants a new NTLMSSP challenge, but "
					  "already got one\n"));
				x_fprintf(x_stdout, "BH\n");
				ntlmssp_end(&ntlmssp_state);
				return;
			}

			if (!NT_STATUS_IS_OK(status = ntlm_auth_start_ntlmssp_server(&ntlmssp_state))) {
				x_fprintf(x_stdout, "BH %s\n", nt_errstr(status));
				return;
			}

			DEBUG(10, ("got NTLMSSP packet:\n"));
			dump_data(10, (const char *)request.negTokenInit.mechToken.data,
				  request.negTokenInit.mechToken.length);

			response.type = SPNEGO_NEG_TOKEN_TARG;
			response.negTokenTarg.supportedMech = SMB_STRDUP(OID_NTLMSSP);
			response.negTokenTarg.mechListMIC = data_blob(NULL, 0);

			status = ntlmssp_update(ntlmssp_state,
						       request.negTokenInit.mechToken,
						       &response.negTokenTarg.responseToken);
		}

#ifdef HAVE_KRB5
		if (strcmp(request.negTokenInit.mechTypes[0], OID_KERBEROS5_OLD) == 0) {

			TALLOC_CTX *mem_ctx = talloc_init("manage_gss_spnego_request");
			char *principal;
			DATA_BLOB ap_rep;
			DATA_BLOB session_key;

			if ( request.negTokenInit.mechToken.data == NULL ) {
				DEBUG(1, ("Client did not provide Kerberos data\n"));
				x_fprintf(x_stdout, "BH\n");
				return;
			}

			response.type = SPNEGO_NEG_TOKEN_TARG;
			response.negTokenTarg.supportedMech = SMB_STRDUP(OID_KERBEROS5_OLD);
			response.negTokenTarg.mechListMIC = data_blob(NULL, 0);
			response.negTokenTarg.responseToken = data_blob(NULL, 0);

			status = ads_verify_ticket(mem_ctx, lp_realm(), 0,
						   &request.negTokenInit.mechToken,
						   &principal, NULL, &ap_rep,
						   &session_key);

			talloc_destroy(mem_ctx);

			/* Now in "principal" we have the name we are
                           authenticated as. */

			if (NT_STATUS_IS_OK(status)) {

				domain = strchr_m(principal, '@');

				if (domain == NULL) {
					DEBUG(1, ("Did not get a valid principal "
						  "from ads_verify_ticket\n"));
					x_fprintf(x_stdout, "BH\n");
					return;
				}

				*domain++ = '\0';
				domain = SMB_STRDUP(domain);
				user = SMB_STRDUP(principal);

				data_blob_free(&ap_rep);

				SAFE_FREE(principal);
			}
		}
#endif

	} else {

		if ( (request.negTokenTarg.supportedMech == NULL) ||
		     ( strcmp(request.negTokenTarg.supportedMech, OID_NTLMSSP) != 0 ) ) {
			/* Kerberos should never send a negTokenTarg, OID_NTLMSSP
			   is the only one we support that sends this stuff */
			DEBUG(1, ("Got a negTokenTarg for something non-NTLMSSP: %s\n",
				  request.negTokenTarg.supportedMech));
			x_fprintf(x_stdout, "BH\n");
			return;
		}

		if (request.negTokenTarg.responseToken.data == NULL) {
			DEBUG(1, ("Got a negTokenTarg without a responseToken!\n"));
			x_fprintf(x_stdout, "BH\n");
			return;
		}

		status = ntlmssp_update(ntlmssp_state,
					       request.negTokenTarg.responseToken,
					       &response.negTokenTarg.responseToken);

		response.type = SPNEGO_NEG_TOKEN_TARG;
		response.negTokenTarg.supportedMech = SMB_STRDUP(OID_NTLMSSP);
		response.negTokenTarg.mechListMIC = data_blob(NULL, 0);

		if (NT_STATUS_IS_OK(status)) {
			user = SMB_STRDUP(ntlmssp_state->user);
			domain = SMB_STRDUP(ntlmssp_state->domain);
			ntlmssp_end(&ntlmssp_state);
		}
	}

	free_spnego_data(&request);

	if (NT_STATUS_IS_OK(status)) {
		response.negTokenTarg.negResult = SPNEGO_ACCEPT_COMPLETED;
		reply_code = "AF";
		pstr_sprintf(reply_argument, "%s\\%s", domain, user);
	} else if (NT_STATUS_EQUAL(status,
				   NT_STATUS_MORE_PROCESSING_REQUIRED)) {
		response.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
		reply_code = "TT";
		pstr_sprintf(reply_argument, "*");
	} else {
		response.negTokenTarg.negResult = SPNEGO_REJECT;
		reply_code = "NA";
		pstrcpy(reply_argument, nt_errstr(status));
	}

	SAFE_FREE(user);
	SAFE_FREE(domain);

	len = write_spnego_data(&token, &response);
	free_spnego_data(&response);

	if (len == -1) {
		DEBUG(1, ("Could not write SPNEGO data blob\n"));
		x_fprintf(x_stdout, "BH\n");
		return;
	}

	reply_base64 = base64_encode_data_blob(token);

	x_fprintf(x_stdout, "%s %s %s\n",
		  reply_code, reply_base64, reply_argument);

	SAFE_FREE(reply_base64);
	data_blob_free(&token);

	return;
}
Exemplo n.º 19
0
static BOOL manage_client_krb5_init(SPNEGO_DATA spnego)
{
	char *principal;
	DATA_BLOB tkt, to_server;
	DATA_BLOB session_key_krb5 = data_blob(NULL, 0);
	SPNEGO_DATA reply;
	char *reply_base64;
	int retval;
	
	const char *my_mechs[] = {OID_KERBEROS5_OLD, NULL};
	ssize_t len;

	if ( (spnego.negTokenInit.mechListMIC.data == NULL) ||
	     (spnego.negTokenInit.mechListMIC.length == 0) ) {
		DEBUG(1, ("Did not get a principal for krb5\n"));
		return False;
	}

	principal = SMB_MALLOC(spnego.negTokenInit.mechListMIC.length+1);

	if (principal == NULL) {
		DEBUG(1, ("Could not malloc principal\n"));
		return False;
	}

	memcpy(principal, spnego.negTokenInit.mechListMIC.data,
	       spnego.negTokenInit.mechListMIC.length);
	principal[spnego.negTokenInit.mechListMIC.length] = '\0';

	retval = cli_krb5_get_ticket(principal, 0, &tkt, &session_key_krb5, 0, NULL);

	if (retval) {

		pstring user;

		/* Let's try to first get the TGT, for that we need a
                   password. */

		if (opt_password == NULL) {
			DEBUG(10, ("Requesting password\n"));
			x_fprintf(x_stdout, "PW\n");
			return True;
		}

		pstr_sprintf(user, "%s@%s", opt_username, opt_domain);

		if ((retval = kerberos_kinit_password(user, opt_password, 0, NULL))) {
			DEBUG(10, ("Requesting TGT failed: %s\n", error_message(retval)));
			return False;
		}

		retval = cli_krb5_get_ticket(principal, 0, &tkt, &session_key_krb5, 0, NULL);

		if (retval) {
			DEBUG(10, ("Kinit suceeded, but getting a ticket failed: %s\n", error_message(retval)));
			return False;
		}
	}

	data_blob_free(&session_key_krb5);

	ZERO_STRUCT(reply);

	reply.type = SPNEGO_NEG_TOKEN_INIT;
	reply.negTokenInit.mechTypes = my_mechs;
	reply.negTokenInit.reqFlags = 0;
	reply.negTokenInit.mechToken = tkt;
	reply.negTokenInit.mechListMIC = data_blob(NULL, 0);

	len = write_spnego_data(&to_server, &reply);
	data_blob_free(&tkt);

	if (len == -1) {
		DEBUG(1, ("Could not write SPNEGO data blob\n"));
		return False;
	}

	reply_base64 = base64_encode_data_blob(to_server);
	x_fprintf(x_stdout, "KK %s *\n", reply_base64);

	SAFE_FREE(reply_base64);
	data_blob_free(&to_server);
	DEBUG(10, ("sent GSS-SPNEGO KERBEROS5 negTokenInit\n"));
	return True;
}
Exemplo n.º 20
0
/****************************************************************************
send a qpathinfo BASIC_INFO call
****************************************************************************/
BOOL cli_qpathinfo_basic( struct cli_state *cli, const char *name, 
                          SMB_STRUCT_STAT *sbuf, uint32 *attributes )
{
	unsigned int param_len = 0;
	unsigned int data_len = 0;
	uint16 setup = TRANSACT2_QPATHINFO;
	char param[sizeof(pstring)+6];
	char *rparam=NULL, *rdata=NULL;
	char *p;
	pstring path;
	int len;
	
	/* send full paths to dfs root shares */
	
	if ( cli->dfsroot )
		pstr_sprintf(path, "\\%s\\%s\\%s", cli->desthost, cli->share, name );
	else
		pstrcpy( path, name );
	
	/* cleanup */
	
	len = strlen( path );
	if ( path[len] == '\\' )
		path[len] = '\0';

	p = param;
	memset(p, 0, 6);
	SSVAL(p, 0, SMB_QUERY_FILE_BASIC_INFO);
	p += 6;
	p += clistr_push(cli, p, path, sizeof(pstring)-6, STR_TERMINATE);
	param_len = PTR_DIFF(p, param);

	if (!cli_send_trans(cli, SMBtrans2,
		NULL,                        /* name */
		-1, 0,                       /* fid, flags */
		&setup, 1, 0,                /* setup, length, max */
		param, param_len, 2,         /* param, length, max */
		NULL,  0, cli->max_xmit      /* data, length, max */
		)) {
			return False;
	}

	if (!cli_receive_trans(cli, SMBtrans2,
		&rparam, &param_len,
		&rdata, &data_len)) {
			return False;
	}

	if (data_len < 36) {
		SAFE_FREE(rdata);
		SAFE_FREE(rparam);
		return False;
	}

	sbuf->st_atime = interpret_long_date( rdata+8 ); /* Access time. */
	sbuf->st_mtime = interpret_long_date( rdata+16 ); /* Write time. */
	sbuf->st_ctime = interpret_long_date( rdata+24 ); /* Change time. */
	
	*attributes = IVAL( rdata, 32 );
	
	SAFE_FREE(rparam);
	SAFE_FREE(rdata);
	
	return True;
}
Exemplo n.º 21
0
int main(int argc, char **argv)
{
	pstring logfile;
	static BOOL interactive = False;
	static BOOL Fork = True;
	static BOOL log_stdout = False;
	struct poptOption long_options[] = {
		POPT_AUTOHELP
		{ "stdout", 'S', POPT_ARG_VAL, &log_stdout, True, "Log to stdout" },
		{ "foreground", 'F', POPT_ARG_VAL, &Fork, False, "Daemon in foreground mode" },
		{ "interactive", 'i', POPT_ARG_NONE, NULL, 'i', "Interactive mode" },
		{ "single-daemon", 'Y', POPT_ARG_VAL, &opt_dual_daemon, False, "Single daemon mode" },
		{ "no-caching", 'n', POPT_ARG_VAL, &opt_nocache, True, "Disable caching" },
		POPT_COMMON_SAMBA
		POPT_TABLEEND
	};
	poptContext pc;
	int opt;

	/* glibc (?) likes to print "User defined signal 1" and exit if a
	   SIGUSR[12] is received before a handler is installed */

 	CatchSignal(SIGUSR1, SIG_IGN);
 	CatchSignal(SIGUSR2, SIG_IGN);

	fault_setup((void (*)(void *))fault_quit );

	/* Initialise for running in non-root mode */

	sec_init();

	set_remote_machine_name("winbindd", False);

	/* Set environment variable so we don't recursively call ourselves.
	   This may also be useful interactively. */

	setenv(WINBINDD_DONT_ENV, "1", 1);

	/* Initialise samba/rpc client stuff */

	pc = poptGetContext("winbindd", argc, (const char **)argv, long_options,
						POPT_CONTEXT_KEEP_FIRST);

	while ((opt = poptGetNextOpt(pc)) != -1) {
		switch (opt) {
			/* Don't become a daemon */
		case 'i':
			interactive = True;
			log_stdout = True;
			Fork = False;
			break;
		}
	}


	if (log_stdout && Fork) {
		printf("Can't log to stdout (-S) unless daemon is in foreground +(-F) or interactive (-i)\n");
		poptPrintUsage(pc, stderr, 0);
		exit(1);
	}

	pstr_sprintf(logfile, "%s/log.winbindd", dyn_LOGFILEBASE);
	lp_set_logfile(logfile);
	setup_logging("winbindd", log_stdout);
	reopen_logs();

	DEBUG(1, ("winbindd version %s started.\n", SAMBA_VERSION_STRING) );
	DEBUGADD( 1, ( "Copyright The Samba Team 2000-2004\n" ) );

	if (!reload_services_file()) {
		DEBUG(0, ("error opening config file\n"));
		exit(1);
	}

	/* Setup names. */

	if (!init_names())
		exit(1);

  	load_interfaces();

	if (!secrets_init()) {

		DEBUG(0,("Could not initialize domain trust account secrets. Giving up\n"));
		return False;
	}

	/* Enable netbios namecache */

	namecache_enable();

	/* Check winbindd parameters are valid */

	ZERO_STRUCT(server_state);

	/* Winbind daemon initialisation */

	if ( (!winbindd_param_init()) || (!winbindd_upgrade_idmap()) ||
	     (!idmap_init(lp_idmap_backend())) ) {
		DEBUG(1, ("Could not init idmap -- netlogon proxy only\n"));
		idmap_proxyonly();
	}

	generate_wellknown_sids();

	/* Unblock all signals we are interested in as they may have been
	   blocked by the parent process. */

	BlockSignals(False, SIGINT);
	BlockSignals(False, SIGQUIT);
	BlockSignals(False, SIGTERM);
	BlockSignals(False, SIGUSR1);
	BlockSignals(False, SIGUSR2);
	BlockSignals(False, SIGHUP);
	BlockSignals(False, SIGCHLD);

	/* Setup signal handlers */
	
	CatchSignal(SIGINT, termination_handler);      /* Exit on these sigs */
	CatchSignal(SIGQUIT, termination_handler);
	CatchSignal(SIGTERM, termination_handler);
	CatchSignal(SIGCHLD, sigchld_handler);

	CatchSignal(SIGPIPE, SIG_IGN);                 /* Ignore sigpipe */

	CatchSignal(SIGUSR2, sigusr2_handler);         /* Debugging sigs */
	CatchSignal(SIGHUP, sighup_handler);

	if (!interactive)
		become_daemon(Fork);

	pidfile_create("winbindd");

#if HAVE_SETPGID
	/*
	 * If we're interactive we want to set our own process group for
	 * signal management.
	 */
	if (interactive)
		setpgid( (pid_t)0, (pid_t)0);
#endif

	if (opt_dual_daemon) {
		do_dual_daemon();
	}

	/* Initialise messaging system */

	if (!message_init()) {
		DEBUG(0, ("unable to initialise messaging system\n"));
		exit(1);
	}
	
	/* React on 'smbcontrol winbindd reload-config' in the same way
	   as to SIGHUP signal */
	message_register(MSG_SMB_CONF_UPDATED, msg_reload_services);
	message_register(MSG_SHUTDOWN, msg_shutdown);
	
	poptFreeContext(pc);

	netsamlogon_cache_init(); /* Non-critical */
	
	init_domain_list();

	/* Loop waiting for requests */

	process_loop();

	trustdom_cache_shutdown();

	return 0;
}
Exemplo n.º 22
0
static void popt_common_callback(poptContext con, 
			   enum poptCallbackReason reason,
			   const struct poptOption *opt,
			   const char *arg, const void *data)
{
	pstring logfile;
	const char *pname;
	
	/* Find out basename of current program */
	pname = strrchr_m(poptGetInvocationName(con),'/');

	if (!pname)
		pname = poptGetInvocationName(con);
	else 
		pname++;

	if (reason == POPT_CALLBACK_REASON_PRE) {
		pstr_sprintf(logfile, "%s/log.%s", dyn_LOGFILEBASE, pname);
		lp_set_logfile(logfile);
		return;
	}

	switch(opt->val) {
	case 'd':
		if (arg) {
			debug_parse_levels(arg);
			AllowDebugChange = False;
		}
		break;

	case 'V':
		printf( "Version %s\n", SAMBA_VERSION_STRING);
		exit(0);
		break;

	case 'O':
		if (arg) {
			pstrcpy(user_socket_options,arg);
		}
		break;

	case 's':
		if (arg) {
			pstrcpy(dyn_CONFIGFILE, arg);
		}
		break;

	case 'n':
		if (arg) {
			set_global_myname(arg);
		}
		break;

	case 'l':
		if (arg) {
			pstr_sprintf(logfile, "%s/log.%s", arg, pname);
			lp_set_logfile(logfile);
		}
		break;

	case 'i':
		if (arg) {
			  set_global_scope(arg);
		}
		break;

	case 'W':
		if (arg) {
			set_global_myworkgroup(arg);
		}
		break;
	}
}
Exemplo n.º 23
0
BOOL regdb_store_keys( const char *key, REGSUBKEY_CTR *ctr )
{
	int num_subkeys, i;
	pstring path;
	REGSUBKEY_CTR *subkeys, *old_subkeys;
	char *oldkeyname;
	
	/* fetch a list of the old subkeys so we can determine if any were deleted */
	
	if ( !(old_subkeys = TALLOC_ZERO_P( ctr, REGSUBKEY_CTR )) ) {
		DEBUG(0,("regdb_store_keys: talloc() failure!\n"));
		return False;
	}

	regdb_fetch_keys( key, old_subkeys );
	
	/* store the subkey list for the parent */
	
	if ( !regdb_store_keys_internal( key, ctr ) ) {
		DEBUG(0,("regdb_store_keys: Failed to store new subkey list for parent [%s}\n", key ));
		return False;
	}
	
	/* now delete removed keys */
	
	num_subkeys = regsubkey_ctr_numkeys( old_subkeys );
	for ( i=0; i<num_subkeys; i++ ) {
		oldkeyname = regsubkey_ctr_specific_key( old_subkeys, i );
		if ( !regsubkey_ctr_key_exists( ctr, oldkeyname ) ) {
			pstr_sprintf( path, "%s%c%s", key, '/', oldkeyname );
			normalize_reg_path( path );
			tdb_delete_bystring( tdb_reg, path );
		}
	}

	TALLOC_FREE( old_subkeys );
	
	/* now create records for any subkeys that don't already exist */
	
	num_subkeys = regsubkey_ctr_numkeys( ctr );
	for ( i=0; i<num_subkeys; i++ ) {
		pstr_sprintf( path, "%s%c%s", key, '/', regsubkey_ctr_specific_key( ctr, i ) );

		if ( !(subkeys = TALLOC_ZERO_P( ctr, REGSUBKEY_CTR )) ) {
			DEBUG(0,("regdb_store_keys: talloc() failure!\n"));
			return False;
		}

		if ( regdb_fetch_keys( path, subkeys ) == -1 ) {
			/* create a record with 0 subkeys */
			if ( !regdb_store_keys_internal( path, subkeys ) ) {
				DEBUG(0,("regdb_store_keys: Failed to store new record for key [%s}\n", path ));
				TALLOC_FREE( subkeys );
				return False;
			}
		}

		TALLOC_FREE( subkeys );
	}
	
	return True;
}