xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/in.ftpd/hostacc.c (revision 0:68f95e015346)
1 #pragma ident	"%Z%%M%	%I%	%E% SMI"
2 
3 /****************************************************************************
4   Copyright (c) 1999,2000 WU-FTPD Development Group.
5   All rights reserved.
6 
7   Portions Copyright (c) 1980, 1985, 1988, 1989, 1990, 1991, 1993, 1994
8     The Regents of the University of California.
9   Portions Copyright (c) 1993, 1994 Washington University in Saint Louis.
10   Portions Copyright (c) 1996, 1998 Berkeley Software Design, Inc.
11   Portions Copyright (c) 1989 Massachusetts Institute of Technology.
12   Portions Copyright (c) 1998 Sendmail, Inc.
13   Portions Copyright (c) 1983, 1995, 1996, 1997 Eric P.  Allman.
14   Portions Copyright (c) 1997 by Stan Barber.
15   Portions Copyright (c) 1997 by Kent Landfield.
16   Portions Copyright (c) 1991, 1992, 1993, 1994, 1995, 1996, 1997
17     Free Software Foundation, Inc.
18 
19   Use and distribution of this software and its source code are governed
20   by the terms and conditions of the WU-FTPD Software License ("LICENSE").
21 
22   If you did not receive a copy of the license, it may be obtained online
23   at http://www.wu-ftpd.org/license.html.
24 
25   $Id: hostacc.c,v 1.8 2000/07/01 18:17:39 wuftpd Exp $
26 
27 ****************************************************************************/
28 /*
29  *      hostacc.c  -  Implementation of host access for the
30  *                    experimental FTP daemon developed at
31  *                    Washington University.
32  *
33  * INITIAL AUTHOR  - Bart Muijzer    <bartm@cv.ruu.nl>
34  *
35  * HISTORY
36  *      930316  BM      Created
37  *      930317  BM      Converted to local naming convention;
38  *                      added rhost_ok(), cleanup code in enghacc()
39  *      930318  BM      Ported to BSD; fixed memory leaks
40  *      930322  BM      Changed algorithm: not in configfile =  allow
41  *                                         in configfile and match = allow|deny
42  *                                         in configfile and no match = deny
43  */
44 #include "config.h"
45 
46 #ifdef  HOST_ACCESS
47 
48 #include "proto.h"
49 #include "hostacc.h"
50 
51 static char linbuf[MAXLEN];	/* Buffer to hold one line of config-file  */
52 static char unibuf[MAXLEN];	/* Buffer to hold unified line             */
53 static hacc_t *ha_arr;		/* Array with host access information      */
54 
55 static FILE *ptFp;		/* FILE * into host access config file     */
56 static int iHaInd = 0;		/* Index in ha_arr                         */
57 static int iHaSize;		/* Will hold actual #elems in ha_arr       */
58 static int iFirstTim = 1;	/* Used by gethacc() to see if index in    */
59 				 /* ha_arr needs to be reset                */
60 
61 /* ------------------------------------------------------------------------ *\
62  * FUNCTION  : rhost_ok                                                     *
63  * PURPOSE   : Check if a host is allowed to make a connection              *
64  * ARGUMENTS : Remote user name, remote host name, remote host address      *
65  * RETURNS   : 1 if host is granted access, 0 if not                        *
66  \* ------------------------------------------------------------------------ */
67 
rhost_ok(char * pcRuser,char * pcRhost,char * pcRaddr)68 int rhost_ok(char *pcRuser, char *pcRhost, char *pcRaddr)
69 {
70     hacc_t *ptHtmp;
71     char *pcHost;
72     char *ha_login;
73     int iInd, iLineMatch = 0, iUserSeen = 0;
74 
75     switch (sethacc()) {
76     case 1:
77 	/* no hostaccess file; disable mechanism */
78 	return (1);
79 	/* break; */
80     case -1:
81 	syslog(LOG_INFO, "rhost_ok: sethacc failed");
82 	endhacc();
83 	return (0);
84 	/* break; */
85     default:
86 	break;
87     }
88 
89     /* user names "ftp" and "anonymous" are equivalent */
90     if (!strcasecmp(pcRuser, "anonymous"))
91 	pcRuser = "ftp";
92 
93     while (((ptHtmp = gethacc()) != (hacc_t *) NULL) && !iLineMatch) {
94 	if (strcasecmp(ptHtmp->ha_login, "anonymous"))
95 	    ha_login = ptHtmp->ha_login;
96 	else
97 	    ha_login = "ftp";
98 
99 	if ((strcasecmp(pcRuser, ha_login)) && strcmp(ha_login, "*"))
100 	    /* wrong user, check rest of file */
101 	    continue;
102 
103 	/*
104 	 * We have seen a line regarding the current user.
105 	 * Remember this.
106 	 */
107 	iUserSeen = 1;
108 
109 	for (iInd = 0, pcHost = ptHtmp->ha_hosts[0];
110 	     ((iInd < MAXHST) && (pcHost != NULL) && !iLineMatch);
111 	     pcHost = ptHtmp->ha_hosts[++iInd]) {
112 	    iLineMatch = hostmatch(pcHost, pcRaddr, pcRhost);
113 	    if (iLineMatch) {
114 		iLineMatch = (ptHtmp->ha_type == ALLOW) ? 1 : 0;
115 		goto match;
116 	    }
117 	}
118     }
119 
120   match:
121     /*
122      * At this point, iUserSeen == 1 if we've seen lines regarding
123      * the current user, and 0 otherwise. If we reached the end of
124      * the config file without a match we allow. Else, we allow or
125      * deny according to the rule found.
126      */
127 
128     if (endhacc()) {
129 	syslog(LOG_INFO, "rhost_ok: endhacc failed");
130 	return (0);
131     }
132 
133     if (iUserSeen)
134 	return (ptHtmp == NULL) ? 0 : iLineMatch;
135     else
136 	/* Nothing at all about user in configfile, allow */
137 	return (1);
138 }
139 
140 /* ------------------------------------------------------------------------ *\
141  * FUNCTION  : sethacc                                                      *
142  * PURPOSE   : Initialize data structures for host access                   *
143  * ARGUMENTS : None                                                         *
144  * RETURNS   : -1 on failure, 1 if host access file doesn't exist,          *
145  *             0 otherwise                                                  *
146  \* ------------------------------------------------------------------------ */
147 
sethacc(void)148 static int sethacc(void)
149 {
150     int iHaHind = 0;		/* Index in list of hosts   */
151     char *pcBegin, *pcEnd, *pcColon;
152     char *pcTmp1, *pcTmp2;
153     int iHaMalloc = 0;		/* how many elem malloced */
154 
155     iHaInd = 0;
156     iFirstTim = 1;
157     /* Open config file */
158     if ((ptFp = fopen(_path_ftphosts, "r")) == NULL) {
159 	if (errno == ENOENT)
160 	    return (1);
161 	else {
162 	    fatalmsg("Can't open host access file");
163 	    iHaSize = iHaInd;
164 	    return (-1);
165 	}
166     }
167     ha_arr = (hacc_t *) malloc((iHaMalloc = 10) * sizeof(hacc_t));
168     if (ha_arr == NULL) {
169 	syslog(LOG_ERR, "malloc error in sethacc");
170 	exit(0);
171     }
172 
173     while (fgets(linbuf, MAXLEN, ptFp) != NULL) {
174 	iHaHind = 0;
175 
176 	/* Find first non-whitespace character */
177 	for (pcBegin = linbuf;
178 	     ((*pcBegin == '\t') || (*pcBegin == ' '));
179 	     pcBegin++);
180 
181 	/* Get rid of comments */
182 	if ((pcEnd = strchr(linbuf, '#')) != NULL)
183 	    *pcEnd = '\0';
184 
185 
186 	/* Skip empty lines */
187 	if ((pcBegin == pcEnd) || (*pcBegin == '\n'))
188 	    continue;
189 
190 	/* Substitute all whitespace by a single ":" so we can
191 	 * easily break on words later on. The easiest way is
192 	 * to copy the result into a temporary buffer (called
193 	 * the "unified buffer" because it will store a line in
194 	 * the same format, regardless of the format the original
195 	 * line was in).
196 	 * The result will look like: "allow:name:host:host:host"
197 	 */
198 	for (pcTmp1 = pcBegin, pcTmp2 = unibuf; *pcTmp1; pcTmp1++) {
199 	    if (*pcTmp1 != '\t' && *pcTmp1 != ' ' && *pcTmp1 != '\n')
200 		*pcTmp2++ = *pcTmp1;
201 	    else
202 		/* whitespace */
203 	    if (*(pcTmp2 - 1) == ':')
204 		continue;
205 	    else
206 		*pcTmp2++ = ':';
207 	}
208 
209 	/* Throw away trailing whitespace, now indicated by
210 	 * the last character of the unified buffer being a
211 	 * colon. Remember where the news string ends.
212 	 */
213 	pcEnd = (*(pcTmp2 - 1) == ':') ? (pcTmp2 - 1) : pcTmp2;
214 	*pcEnd = '\0';		/* Terminate new string */
215 
216 	/*
217 	 * Check if we need to expand the array with
218 	 * host access information
219 	 */
220 	if (iHaInd >= iHaMalloc) {
221 	    ha_arr = (hacc_t *) realloc(ha_arr, (iHaMalloc += 10) * sizeof(hacc_t));
222 	    if (!ha_arr) {
223 		fatalmsg("Failed to realloc host access array");
224 		iHaSize = iHaInd;
225 		return (-1);
226 	    }
227 	}
228 
229 	/* Store what's left of the line into the
230 	 * hacc_t structure. First the access type,
231 	 * then the loginname, and finally a list of
232 	 * hosts to which all this applies.
233 	 */
234 	pcBegin = unibuf;
235 	if (!strncmp(pcBegin, "deny", 4)) {
236 	    ha_arr[iHaInd].ha_type = DENY;
237 	    pcBegin += 5;
238 	}
239 	else if (!strncmp(pcBegin, "allow", 5)) {
240 	    ha_arr[iHaInd].ha_type = ALLOW;
241 	    pcBegin += 6;
242 	}
243 	else {
244 	    fatalmsg("Format error in host access file");
245 	    iHaSize = iHaInd;
246 	    return (-1);
247 	}
248 
249 	if ((pcColon = strchr(pcBegin, ':')) != NULL)
250 	    ha_arr[iHaInd].ha_login =
251 		strnsav(pcBegin, (pcColon - pcBegin));
252 	else {
253 	    fatalmsg("Format error in host access file");
254 	    iHaSize = iHaInd;
255 	    return (-1);
256 	}
257 
258 	pcBegin = pcColon + 1;
259 	while ((pcColon = strchr(pcBegin, ':')) != NULL) {
260 	    ha_arr[iHaInd].ha_hosts[iHaHind++] =
261 		strnsav(pcBegin, (pcColon - pcBegin));
262 	    pcBegin = pcColon + 1;
263 	    if (iHaHind >= MAXHST) {
264 		fatalmsg("Line too long");
265 		iHaSize = iHaInd;
266 		return (-1);
267 	    }
268 	}
269 	ha_arr[iHaInd].ha_hosts[iHaHind++] =
270 	    strnsav(pcBegin, (pcEnd - pcBegin));
271 	ha_arr[iHaInd].ha_hosts[iHaHind] = NULL;
272 	iHaInd++;
273     }
274     iHaSize = iHaInd;		/* Record current size of ha_arr */
275     return ((feof(ptFp)) ? 0 : -1);
276 }
277 
278 /* ------------------------------------------------------------------------ *\
279  * FUNCTION  : gethacc                                                      *
280  * PURPOSE   : return pointer to the next host_access structure             *
281  * ARGUMENTS : None                                                         *
282  * RETURNS   : NULL on failure, pointervalue otherwise                      *
283  \* ------------------------------------------------------------------------ */
284 
gethacc(void)285 static hacc_t *gethacc(void)
286 {
287     static int iHaInd;
288     static hacc_t ptTmp;
289 
290     if (iFirstTim) {
291 	iFirstTim = 0;
292 	iHaInd = 0;
293     }
294     if (iHaInd >= iHaSize)
295 	return ((hacc_t *) NULL);
296     else {
297 	memmove(&ptTmp, &(ha_arr[iHaInd]), sizeof(hacc_t));
298 	iHaInd++;
299 	return (&ptTmp);
300     }
301 }
302 
303 /* ------------------------------------------------------------------------ *\
304  * FUNCTION  : endhacc                                                      *
305  * PURPOSE   : Free allocated data structures for host access               *
306  * ARGUMENTS : None                                                         *
307  * RETURNS   : -1 on failure, 0 otherwise                                   *
308  \* ------------------------------------------------------------------------ */
309 
endhacc(void)310 static int endhacc(void)
311 {
312     int iInd;
313     hacc_t *ptHtmp;
314 
315     if (ha_arr == (hacc_t *) NULL)
316 	return (0);
317 
318     for (ptHtmp = ha_arr;
319 	 ptHtmp < ha_arr + iHaSize && ptHtmp->ha_type;
320 	 ptHtmp++) {
321 	ptHtmp->ha_type = 0;
322 	if (ptHtmp->ha_login) {
323 	    free(ptHtmp->ha_login);
324 	    ptHtmp->ha_login = NULL;
325 	}
326 	for (iInd = 0;
327 	     iInd < MAXHST && ptHtmp->ha_hosts[iInd];
328 	     iInd++) {
329 	    free(ptHtmp->ha_hosts[iInd]);
330 	    ptHtmp->ha_hosts[iInd] = NULL;
331 	}
332     }
333     free(ha_arr);
334     ha_arr = NULL;
335 
336     if (ptFp && fclose(ptFp))
337 	return (-1);
338     return (0);
339 }
340 
341 /* ------------------------------------------------------------------------ */
342 
fatalmsg(char * pcMsg)343 static void fatalmsg(char *pcMsg)
344 {
345     syslog(LOG_INFO, "host_access: %s", pcMsg);
346 }
347 
strnsav(char * pcStr,int iLen)348 static char *strnsav(char *pcStr, int iLen)
349 {
350     char *pcBuf;
351 
352     if ((pcBuf = (char *) malloc(iLen + 1)) == NULL)
353 	return (NULL);
354     strncpy(pcBuf, pcStr, iLen);
355     pcBuf[iLen] = '\0';
356     return (pcBuf);
357 }
358 
359 #endif /* HOST_ACCESS */
360