| 
									
										
										
										
											2008-01-10 17:10:23 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  *  fs/cifs/dns_resolve.c | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *   Copyright (c) 2007 Igor Mammedov | 
					
						
							|  |  |  |  *   Author(s): Igor Mammedov (niallain@gmail.com) | 
					
						
							|  |  |  |  *              Steve French (sfrench@us.ibm.com) | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *   Contains the CIFS DFS upcall routines used for hostname to | 
					
						
							|  |  |  |  *   IP address translation. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *   This library is free software; you can redistribute it and/or modify | 
					
						
							|  |  |  |  *   it under the terms of the GNU Lesser General Public License as published | 
					
						
							|  |  |  |  *   by the Free Software Foundation; either version 2.1 of the License, or | 
					
						
							|  |  |  |  *   (at your option) any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *   This library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  *   but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See | 
					
						
							|  |  |  |  *   the GNU Lesser General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *   You should have received a copy of the GNU Lesser General Public License | 
					
						
							|  |  |  |  *   along with this library; if not, write to the Free Software | 
					
						
							|  |  |  |  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <keys/user-type.h>
 | 
					
						
							|  |  |  | #include "dns_resolve.h"
 | 
					
						
							|  |  |  | #include "cifsglob.h"
 | 
					
						
							|  |  |  | #include "cifsproto.h"
 | 
					
						
							|  |  |  | #include "cifs_debug.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-23 18:46:07 +00:00
										 |  |  | /* Checks if supplied name is IP address
 | 
					
						
							|  |  |  |  * returns: | 
					
						
							|  |  |  |  * 		1 - name is IP | 
					
						
							|  |  |  |  * 		0 - name is not IP | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int | 
					
						
							| 
									
										
										
										
											2009-06-11 10:27:31 -04:00
										 |  |  | is_ip(char *name) | 
					
						
							| 
									
										
										
										
											2008-09-23 18:46:07 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-06-11 10:27:30 -04:00
										 |  |  | 	struct sockaddr_storage ss; | 
					
						
							| 
									
										
										
										
											2008-09-23 18:46:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-11 10:27:30 -04:00
										 |  |  | 	return cifs_convert_address(name, &ss); | 
					
						
							| 
									
										
										
										
											2008-09-23 18:46:07 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | dns_resolver_instantiate(struct key *key, const void *data, | 
					
						
							| 
									
										
										
										
											2008-01-10 17:10:23 +00:00
										 |  |  | 		size_t datalen) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int rc = 0; | 
					
						
							|  |  |  | 	char *ip; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-23 18:46:07 +00:00
										 |  |  | 	ip = kmalloc(datalen + 1, GFP_KERNEL); | 
					
						
							| 
									
										
										
										
											2008-01-10 17:10:23 +00:00
										 |  |  | 	if (!ip) | 
					
						
							|  |  |  | 		return -ENOMEM; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	memcpy(ip, data, datalen); | 
					
						
							|  |  |  | 	ip[datalen] = '\0'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-23 18:46:07 +00:00
										 |  |  | 	/* make sure this looks like an address */ | 
					
						
							| 
									
										
										
										
											2009-06-11 10:27:31 -04:00
										 |  |  | 	if (!is_ip(ip)) { | 
					
						
							| 
									
										
										
										
											2008-09-23 18:46:07 +00:00
										 |  |  | 		kfree(ip); | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	key->type_data.x[0] = datalen; | 
					
						
							| 
									
										
										
										
											2009-03-23 01:47:11 -04:00
										 |  |  | 	key->payload.data = ip; | 
					
						
							| 
									
										
										
										
											2008-01-10 17:10:23 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return rc; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-27 17:53:30 +00:00
										 |  |  | static void | 
					
						
							|  |  |  | dns_resolver_destroy(struct key *key) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	kfree(key->payload.data); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-01-10 17:10:23 +00:00
										 |  |  | struct key_type key_type_dns_resolver = { | 
					
						
							|  |  |  | 	.name        = "dns_resolver", | 
					
						
							|  |  |  | 	.def_datalen = sizeof(struct in_addr), | 
					
						
							|  |  |  | 	.describe    = user_describe, | 
					
						
							|  |  |  | 	.instantiate = dns_resolver_instantiate, | 
					
						
							| 
									
										
										
										
											2008-08-27 17:53:30 +00:00
										 |  |  | 	.destroy     = dns_resolver_destroy, | 
					
						
							| 
									
										
										
										
											2008-01-10 17:10:23 +00:00
										 |  |  | 	.match       = user_match, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Resolves server name to ip address.
 | 
					
						
							|  |  |  |  * input: | 
					
						
							|  |  |  |  * 	unc - server UNC | 
					
						
							|  |  |  |  * output: | 
					
						
							|  |  |  |  * 	*ip_addr - pointer to server ip, caller responcible for freeing it. | 
					
						
							|  |  |  |  * return 0 on success | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | int | 
					
						
							| 
									
										
										
										
											2008-01-25 10:12:41 +00:00
										 |  |  | dns_resolve_server_name_to_ip(const char *unc, char **ip_addr) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-01-10 17:10:23 +00:00
										 |  |  | 	int rc = -EAGAIN; | 
					
						
							| 
									
										
										
										
											2008-04-26 00:22:23 +00:00
										 |  |  | 	struct key *rkey = ERR_PTR(-EAGAIN); | 
					
						
							| 
									
										
										
										
											2008-01-10 17:10:23 +00:00
										 |  |  | 	char *name; | 
					
						
							| 
									
										
										
										
											2008-04-26 00:22:23 +00:00
										 |  |  | 	char *data = NULL; | 
					
						
							| 
									
										
										
										
											2008-01-10 17:10:23 +00:00
										 |  |  | 	int len; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-01-25 10:12:41 +00:00
										 |  |  | 	if (!ip_addr || !unc) | 
					
						
							| 
									
										
										
										
											2008-01-10 17:10:23 +00:00
										 |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* search for server name delimiter */ | 
					
						
							|  |  |  | 	len = strlen(unc); | 
					
						
							|  |  |  | 	if (len < 3) { | 
					
						
							| 
									
										
										
										
											2008-03-10 17:14:34 +00:00
										 |  |  | 		cFYI(1, ("%s: unc is too short: %s", __func__, unc)); | 
					
						
							| 
									
										
										
										
											2008-01-10 17:10:23 +00:00
										 |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	len -= 2; | 
					
						
							|  |  |  | 	name = memchr(unc+2, '\\', len); | 
					
						
							|  |  |  | 	if (!name) { | 
					
						
							|  |  |  | 		cFYI(1, ("%s: probably server name is whole unc: %s", | 
					
						
							| 
									
										
										
										
											2008-03-10 17:14:34 +00:00
										 |  |  | 					__func__, unc)); | 
					
						
							| 
									
										
										
										
											2008-01-10 17:10:23 +00:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		len = (name - unc) - 2/* leading // */; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	name = kmalloc(len+1, GFP_KERNEL); | 
					
						
							|  |  |  | 	if (!name) { | 
					
						
							|  |  |  | 		rc = -ENOMEM; | 
					
						
							|  |  |  | 		return rc; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	memcpy(name, unc+2, len); | 
					
						
							|  |  |  | 	name[len] = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-26 00:22:23 +00:00
										 |  |  | 	if (is_ip(name)) { | 
					
						
							|  |  |  | 		cFYI(1, ("%s: it is IP, skipping dns upcall: %s", | 
					
						
							|  |  |  | 					__func__, name)); | 
					
						
							|  |  |  | 		data = name; | 
					
						
							|  |  |  | 		goto skip_upcall; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-01-10 17:10:23 +00:00
										 |  |  | 	rkey = request_key(&key_type_dns_resolver, name, ""); | 
					
						
							|  |  |  | 	if (!IS_ERR(rkey)) { | 
					
						
							| 
									
										
										
										
											2008-09-23 18:46:07 +00:00
										 |  |  | 		len = rkey->type_data.x[0]; | 
					
						
							| 
									
										
										
										
											2008-04-26 00:22:23 +00:00
										 |  |  | 		data = rkey->payload.data; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		cERROR(1, ("%s: unable to resolve: %s", __func__, name)); | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | skip_upcall: | 
					
						
							|  |  |  | 	if (data) { | 
					
						
							| 
									
										
										
										
											2008-09-23 18:46:07 +00:00
										 |  |  | 		*ip_addr = kmalloc(len + 1, GFP_KERNEL); | 
					
						
							| 
									
										
										
										
											2008-04-26 00:22:23 +00:00
										 |  |  | 		if (*ip_addr) { | 
					
						
							| 
									
										
										
										
											2008-09-23 18:46:07 +00:00
										 |  |  | 			memcpy(*ip_addr, data, len + 1); | 
					
						
							| 
									
										
										
										
											2008-05-20 13:02:01 +04:00
										 |  |  | 			if (!IS_ERR(rkey)) | 
					
						
							|  |  |  | 				cFYI(1, ("%s: resolved: %s to %s", __func__, | 
					
						
							|  |  |  | 							name, | 
					
						
							|  |  |  | 							*ip_addr | 
					
						
							|  |  |  | 					)); | 
					
						
							| 
									
										
										
										
											2008-01-10 17:10:23 +00:00
										 |  |  | 			rc = 0; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			rc = -ENOMEM; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-04-26 00:22:23 +00:00
										 |  |  | 		if (!IS_ERR(rkey)) | 
					
						
							|  |  |  | 			key_put(rkey); | 
					
						
							| 
									
										
										
										
											2008-01-10 17:10:23 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-26 00:22:23 +00:00
										 |  |  | out: | 
					
						
							| 
									
										
										
										
											2008-01-10 17:10:23 +00:00
										 |  |  | 	kfree(name); | 
					
						
							|  |  |  | 	return rc; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 |