diff options
-rw-r--r-- | source3/Makefile.in | 5 | ||||
-rw-r--r-- | source3/include/proto.h | 5 | ||||
-rw-r--r-- | source3/lib/access.c | 385 | ||||
-rw-r--r-- | source3/smbd/server.c | 12 |
4 files changed, 183 insertions, 224 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in index 1f975d48c5..48f597c9fc 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -87,7 +87,7 @@ LIB_OBJ = lib/charcnv.o lib/charset.o lib/debug.o lib/fault.o \ lib/getsmbpass.o lib/interface.o lib/kanji.o lib/md4.o \ lib/membuffer.o lib/netmask.o lib/pidfile.o lib/replace.o \ lib/signal.o lib/slprintf.o lib/system.o lib/time.o lib/ufc.o \ - lib/util.o lib/genrand.o lib/username.o + lib/util.o lib/genrand.o lib/username.o lib/access.o UBIQX_OBJ = ubiqx/ubi_BinTree.o ubiqx/ubi_Cache.o ubiqx/ubi_SplayTree.o \ ubiqx/ubi_dLinkList.o ubiqx/ubi_sLinkList.o @@ -119,7 +119,7 @@ LOCKING_OBJ = locking/locking.o locking/locking_shm.o locking/locking_slow.o \ PASSDB_OBJ = passdb/passdb.o passdb/smbpassfile.o passdb/smbpass.o \ passdb/pass_check.o -SMBD_OBJ1 = smbd/server.o smbd/access.o smbd/chgpasswd.o smbd/connection.o \ +SMBD_OBJ1 = smbd/server.o smbd/chgpasswd.o smbd/connection.o \ smbd/dfree.o smbd/dir.o smbd/password.o \ smbd/groupname.o smbd/ipc.o smbd/ldap.o smbd/mangle.o \ smbd/message.o smbd/nispass.o smbd/nttrans.o \ @@ -164,7 +164,6 @@ STATUS_OBJ = utils/status.o $(LOCKING_OBJ) $(PARAM_OBJ) \ $(UBIQX_OBJ) $(LIB_OBJ) TESTPARM_OBJ = utils/testparm.o \ - smbd/access.o \ $(PARAM_OBJ) $(UBIQX_OBJ) $(LIB_OBJ) TESTPRNS_OBJ = utils/testprns.o $(PARAM_OBJ) $(UBIQX_OBJ) \ diff --git a/source3/include/proto.h b/source3/include/proto.h index d9a35aa33f..e3189a2d08 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -1844,8 +1844,9 @@ BOOL api_wkssvc_rpc(pipes_struct *p, prs_struct *data); /*The following definitions come from smbd/access.c */ -BOOL check_access(int snum); -BOOL allow_access(char *deny_list,char *allow_list,char *cname,char *caddr); +BOOL allow_access(char *deny_list,char *allow_list, + char *cname,char *caddr); +BOOL check_access(int sock, char *allow_list, char *deny_list); /*The following definitions come from smbd/chgpasswd.c */ diff --git a/source3/lib/access.c b/source3/lib/access.c index a565f437da..d2286e2515 100644 --- a/source3/lib/access.c +++ b/source3/lib/access.c @@ -1,119 +1,133 @@ /* -This module is an adaption of code from the tcpd-1.4 package written -by Wietse Venema, Eindhoven University of Technology, The Netherlands. + This module is an adaption of code from the tcpd-1.4 package written + by Wietse Venema, Eindhoven University of Technology, The Netherlands. -The code is used here with permission. + The code is used here with permission. -The code has been considerably changed from the original. Bug reports -should be sent to samba-bugs@samba.anu.edu.au + The code has been considerably changed from the original. Bug reports + should be sent to samba-bugs@samba.anu.edu.au */ #include "includes.h" -#define ALLOW_PURE_ADDRESSES - extern int DEBUGLEVEL; -#ifndef INADDR_NONE -#define INADDR_NONE ((uint32)~0) -#endif - - -#define Good True -#define Bad False - -#define CLIENT_MATCH client_match - /* Delimiters for lists of daemons or clients. */ +static char *sep = ", \t"; -static char sep[] = ", \t"; - -/* Constants to be used in assignments only, not in comparisons... */ - -#define YES 1 -#define NO 0 #define FAIL (-1) -/* Forward declarations. */ -static int list_match(char *list,char *item, int (*match_fn)(char *, char *)); -static int client_match(char *tok,char *item); -static int string_match(char *tok,char *s); -static int masked_match(char *tok, char *slash, char *s); - -/* Size of logical line buffer. */ -#define BUFLEN 2048 - -/* return true if access should be allowed to a service*/ -BOOL check_access(int snum) +/* masked_match - match address against netnumber/netmask */ +static int masked_match(char *tok, char *slash, char *s) { - char *denyl,*allowl; - BOOL ret = False; - - denyl = lp_hostsdeny(snum); - if (denyl) denyl = strdup(denyl); - - allowl = lp_hostsallow(snum); - if (allowl) allowl = strdup(allowl); - - if ((!denyl || *denyl==0) && (!allowl || *allowl==0)) - ret = True; - - if (!ret) - { - extern int Client; - if (allow_access(denyl,allowl,client_name(Client),client_addr(Client))) - { - if (snum >= 0) - DEBUG(2,("Allowed connection from %s (%s) to %s\n", - client_name(Client),client_addr(Client), - lp_servicename(snum))); - ret = True; + uint32 net; + uint32 mask; + uint32 addr; + + if ((addr = interpret_addr(s)) == INADDR_NONE) + return (False); + *slash = 0; + net = interpret_addr(tok); + *slash = '/'; + if (net == INADDR_NONE || + (mask = interpret_addr(slash + 1)) == INADDR_NONE) { + DEBUG(0,("access: bad net/mask access control: %s", tok)); + return (False); } - else - if (snum >= 0) - DEBUG( 0, ( "Denied connection from %s (%s) to %s\n", - client_name(Client),client_addr(Client), - lp_servicename(snum) ) ); - } - - if (denyl) free(denyl); - if (allowl) free(allowl); - return(ret); + return ((addr & mask) == net); } - -/* return true if access should be allowed */ -BOOL allow_access(char *deny_list,char *allow_list,char *cname,char *caddr) +/* string_match - match string against token */ +static int string_match(char *tok,char *s) { - char *client[2]; - - client[0] = cname; - client[1] = caddr; - - /* if theres no deny list and no allow list then allow access */ - if ((!deny_list || *deny_list == 0) && (!allow_list || *allow_list == 0)) - return(True); - - /* if there is an allow list but no deny list then allow only hosts - on the allow list */ - if (!deny_list || *deny_list == 0) - return(list_match(allow_list,(char *)client,CLIENT_MATCH)); + int tok_len; + int str_len; + char *cut; + + /* Return True if a token has the magic value "ALL". Return + * FAIL if the token is "FAIL". If the token starts with a "." + * (domain name), return True if it matches the last fields of + * the string. If the token has the magic value "LOCAL", + * return True if the string does not contain a "." + * character. If the token ends on a "." (network number), + * return True if it matches the first fields of the + * string. If the token begins with a "@" (netgroup name), + * return True if the string is a (host) member of the + * netgroup. Return True if the token fully matches the + * string. If the token is a netnumber/netmask pair, return + * True if the address is a member of the specified subnet. */ + + if (tok[0] == '.') { /* domain: match last fields */ + if ((str_len = strlen(s)) > (tok_len = strlen(tok)) + && strcasecmp(tok, s + str_len - tok_len) == 0) + return (True); + } else if (tok[0] == '@') { /* netgroup: look it up */ +#ifdef HAVE_NETGROUP + static char *mydomain = NULL; + char *hostname = NULL; + BOOL netgroup_ok = False; + + if (!mydomain) yp_get_default_domain(&mydomain); + + if (!mydomain) { + DEBUG(0,("Unable to get default yp domain.\n")); + return False; + } + if (!(hostname = strdup(s))) { + DEBUG(1,("out of memory for strdup!\n")); + return False; + } + + netgroup_ok = innetgr(tok + 1, hostname, (char *) 0, mydomain); + + DEBUG(5,("looking for %s of domain %s in netgroup %s gave %s\n", + hostname, + mydomain, + tok+1, + BOOLSTR(netgroup_ok))); + + free(hostname); + + if (netgroup_ok) return(True); +#else + DEBUG(0,("access: netgroup support is not configured\n")); + return (False); +#endif + } else if (strcasecmp(tok, "ALL") == 0) { /* all: match any */ + return (True); + } else if (strcasecmp(tok, "FAIL") == 0) { /* fail: match any */ + return (FAIL); + } else if (strcasecmp(tok, "LOCAL") == 0) { /* local: no dots */ + if (strchr(s, '.') == 0 && strcasecmp(s, "unknown") != 0) + return (True); + } else if (!strcasecmp(tok, s)) { /* match host name or address */ + return (True); + } else if (tok[(tok_len = strlen(tok)) - 1] == '.') { /* network */ + if (strncmp(tok, s, tok_len) == 0) + return (True); + } else if ((cut = strchr(tok, '/')) != 0) { /* netnumber/netmask */ + if (isdigit(s[0]) && masked_match(tok, cut, s)) + return (True); + } + return (False); +} - /* if theres a deny list but no allow list then allow - all hosts not on the deny list */ - if (!allow_list || *allow_list == 0) - return(!list_match(deny_list,(char *)client,CLIENT_MATCH)); - /* if there are both type of list then allow all hosts on the allow list */ - if (list_match(allow_list,(char *)client,CLIENT_MATCH)) - return (True); +/* client_match - match host name and address against token */ +static int client_match(char *tok,char *item) +{ + char **client = (char **)item; + int match; - /* if there are both type of list and it's not on the allow then - allow it if its not on the deny */ - if (list_match(deny_list,(char *)client,CLIENT_MATCH)) - return (False); + /* + * Try to match the address first. If that fails, try to match the host + * name if available. + */ - return (True); + if ((match = string_match(tok, client[1])) == 0) + if (client[0][0] != 0) + match = string_match(tok, client[0]); + return (match); } /* list_match - match an item against a list of tokens with exceptions */ @@ -122,7 +136,7 @@ static int list_match(char *list,char *item, int (*match_fn)(char *, char *)) { char *tok; char *listcopy; /* jkf */ - int match = NO; + int match = False; /* * jkf@soton.ac.uk -- 31 August 1994 -- Stop list_match() @@ -142,149 +156,88 @@ static int list_match(char *list,char *item, int (*match_fn)(char *, char *)) for (tok = strtok(listcopy, sep); tok ; tok = strtok(NULL, sep)) { if (strcasecmp(tok, "EXCEPT") == 0) /* EXCEPT: give up */ break; - if ((match = (*match_fn) (tok, item))) /* YES or FAIL */ + if ((match = (*match_fn) (tok, item))) /* True or FAIL */ break; } - /* Process exceptions to YES or FAIL matches. */ + /* Process exceptions to True or FAIL matches. */ - if (match != NO) { + if (match != False) { while ((tok = strtok((char *) 0, sep)) && strcasecmp(tok, "EXCEPT")) /* VOID */ ; - if (tok == 0 || list_match((char *) 0, item, match_fn) == NO) { + if (tok == 0 || list_match((char *) 0, item, match_fn) == False) { if (listcopy != 0) free(listcopy); /* jkf */ return (match); } } if (listcopy != 0) free(listcopy); /* jkf */ - return (NO); + return (False); } -/* client_match - match host name and address against token */ -static int client_match(char *tok,char *item) -{ - char **client = (char **)item; - int match; - - /* - * Try to match the address first. If that fails, try to match the host - * name if available. - */ - - if ((match = string_match(tok, client[1])) == 0) - if (client[0][0] != 0) - match = string_match(tok, client[0]); - return (match); -} - -/* string_match - match string against token */ -static int string_match(char *tok,char *s) +/* return true if access should be allowed */ +BOOL allow_access(char *deny_list,char *allow_list, + char *cname,char *caddr) { - int tok_len; - int str_len; - char *cut; + char *client[2]; - /* - * Return YES if a token has the magic value "ALL". Return FAIL if the - * token is "FAIL". If the token starts with a "." (domain name), return - * YES if it matches the last fields of the string. If the token has the - * magic value "LOCAL", return YES if the string does not contain a "." - * character. If the token ends on a "." (network number), return YES if - * it matches the first fields of the string. If the token begins with a - * "@" (netgroup name), return YES if the string is a (host) member of - * the netgroup. Return YES if the token fully matches the string. If the - * token is a netnumber/netmask pair, return YES if the address is a - * member of the specified subnet. - */ + client[0] = cname; + client[1] = caddr; - if (tok[0] == '.') { /* domain: match last fields */ - if ((str_len = strlen(s)) > (tok_len = strlen(tok)) - && strcasecmp(tok, s + str_len - tok_len) == 0) - return (YES); - } else if (tok[0] == '@') { /* netgroup: look it up */ -#ifdef HAVE_NETGROUP - static char *mydomain = NULL; - char *hostname = NULL; - BOOL netgroup_ok = False; - - if (!mydomain) yp_get_default_domain(&mydomain); - - if (!mydomain) { - DEBUG(0,("Unable to get default yp domain.\n")); - return NO; - } - if (!(hostname = strdup(s))) { - DEBUG(1,("out of memory for strdup!\n")); - return NO; - } - - netgroup_ok = innetgr(tok + 1, hostname, (char *) 0, mydomain); - - DEBUG(5,("looking for %s of domain %s in netgroup %s gave %s\n", - hostname, - mydomain, - tok+1, - BOOLSTR(netgroup_ok))); - -#ifdef NETGROUP_INSECURE - /* if you really want netgroups that match non qualified names - then define NETGROUP_INSECURE. It can, however, be a big - security hole */ - { - char *clnt_domain; - if (!netgroup_ok && (clnt_domain=strchr(hostname,'.'))) { - *clnt_domain++ = '\0'; - netgroup_ok = innetgr(tok + 1, hostname, (char *) 0, mydomain); + /* if theres no deny list and no allow list then allow access */ + if ((!deny_list || *deny_list == 0) && + (!allow_list || *allow_list == 0)) { + return(True); } - } -#endif - free(hostname); - - if (netgroup_ok) return(YES); -#else - DEBUG(0,("access: netgroup support is not configured\n")); - return (NO); -#endif - } else if (strcasecmp(tok, "ALL") == 0) { /* all: match any */ - return (YES); - } else if (strcasecmp(tok, "FAIL") == 0) { /* fail: match any */ - return (FAIL); - } else if (strcasecmp(tok, "LOCAL") == 0) { /* local: no dots */ - if (strchr(s, '.') == 0 && strcasecmp(s, "unknown") != 0) - return (YES); - } else if (!strcasecmp(tok, s)) { /* match host name or address */ - return (YES); - } else if (tok[(tok_len = strlen(tok)) - 1] == '.') { /* network */ - if (strncmp(tok, s, tok_len) == 0) - return (YES); - } else if ((cut = strchr(tok, '/')) != 0) { /* netnumber/netmask */ - if (isdigit(s[0]) && masked_match(tok, cut, s)) - return (YES); - } - return (NO); + /* if there is an allow list but no deny list then allow only hosts + on the allow list */ + if (!deny_list || *deny_list == 0) + return(list_match(allow_list,(char *)client,client_match)); + + /* if theres a deny list but no allow list then allow + all hosts not on the deny list */ + if (!allow_list || *allow_list == 0) + return(!list_match(deny_list,(char *)client,client_match)); + + /* if there are both type of list then allow all hosts on the + allow list */ + if (list_match(allow_list,(char *)client,client_match)) + return (True); + + /* if there are both type of list and it's not on the allow then + allow it if its not on the deny */ + if (list_match(deny_list,(char *)client,client_match)) + return (False); + + return (True); } -/* masked_match - match address against netnumber/netmask */ -static int masked_match(char *tok, char *slash, char *s) +/* return true if access should be allowed to a service for a socket */ +BOOL check_access(int sock, char *allow_list, char *deny_list) { - uint32 net; - uint32 mask; - uint32 addr; - - if ((addr = interpret_addr(s)) == INADDR_NONE) - return (NO); - *slash = 0; - net = interpret_addr(tok); - *slash = '/'; - if (net == INADDR_NONE || (mask = interpret_addr(slash + 1)) == INADDR_NONE) { - DEBUG(0,("access: bad net/mask access control: %s", tok)); - return (NO); - } - return ((addr & mask) == net); -} - + BOOL ret = False; + + if (deny_list) deny_list = strdup(deny_list); + if (allow_list) allow_list = strdup(allow_list); + if ((!deny_list || *deny_list==0) && (!allow_list || *allow_list==0)) { + ret = True; + } + if (!ret) { + if (allow_access(deny_list,allow_list, + client_name(sock),client_addr(sock))) { + DEBUG(2,("Allowed connection from %s (%s)\n", + client_name(sock),client_addr(sock))); + ret = True; + } else { + DEBUG(0,("Denied connection from %s (%s)\n", + client_name(sock),client_addr(sock))); + } + } + if (deny_list) free(deny_list); + if (allow_list) free(allow_list); + return(ret); +} diff --git a/source3/smbd/server.c b/source3/smbd/server.c index 8f9349f3fc..47fb175d8e 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -2679,7 +2679,7 @@ static void process_smb(char *inbuf, char *outbuf) deny parameters before doing any parsing of the packet passed to us by the client. This prevents attacks on our parsing code from hosts not in the hosts allow list */ - if (!check_access(-1)) { + if (!check_access(Client, lp_hostsallow(-1), lp_hostsdeny(-1))) { /* send a negative session response "not listining on calling name" */ static unsigned char buf[5] = {0x83, 0, 0, 1, 0x81}; @@ -3459,6 +3459,7 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de connection_struct *pcon; BOOL guest = False; BOOL force = False; + extern int Client; strlower(service); @@ -3503,7 +3504,8 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de } } - if (!lp_snum_ok(snum) || !check_access(snum)) { + if (!lp_snum_ok(snum) || + !check_access(Client, lp_hostsallow(snum), lp_hostsdeny(snum))) { return(-4); } @@ -4649,6 +4651,7 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize static int num_smb_messages = sizeof(smb_messages) / sizeof(struct smb_message_struct); int match; + extern int Client; #if PROFILING struct timeval msg_start_time; @@ -4756,8 +4759,11 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize return(ERROR(ERRSRV,ERRaccess)); /* does this protocol need to be run as guest? */ - if ((flags & AS_GUEST) && (!become_guest() || !check_access(-1))) + if ((flags & AS_GUEST) && + (!become_guest() || + !check_access(Client, lp_hostsallow(-1), lp_hostsdeny(-1)))) { return(ERROR(ERRSRV,ERRaccess)); + } last_inbuf = inbuf; |