Home | History | Annotate | Download | only in in.ftpd
      1 /*
      2  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
      3  * Use is subject to license terms.
      4  */
      5 
      6 #pragma ident	"%Z%%M%	%I%	%E% SMI"
      7 
      8 /****************************************************************************
      9   Copyright (c) 1999,2000 WU-FTPD Development Group.
     10   All rights reserved.
     11 
     12   Portions Copyright (c) 1980, 1985, 1988, 1989, 1990, 1991, 1993, 1994
     13     The Regents of the University of California.
     14   Portions Copyright (c) 1993, 1994 Washington University in Saint Louis.
     15   Portions Copyright (c) 1996, 1998 Berkeley Software Design, Inc.
     16   Portions Copyright (c) 1989 Massachusetts Institute of Technology.
     17   Portions Copyright (c) 1998 Sendmail, Inc.
     18   Portions Copyright (c) 1983, 1995, 1996, 1997 Eric P.  Allman.
     19   Portions Copyright (c) 1997 by Stan Barber.
     20   Portions Copyright (c) 1997 by Kent Landfield.
     21   Portions Copyright (c) 1991, 1992, 1993, 1994, 1995, 1996, 1997
     22     Free Software Foundation, Inc.
     23 
     24   Use and distribution of this software and its source code are governed
     25   by the terms and conditions of the WU-FTPD Software License ("LICENSE").
     26 
     27   If you did not receive a copy of the license, it may be obtained online
     28   at http://www.wu-ftpd.org/license.html.
     29 
     30   $Id: private.c,v 1.12 2000/07/01 18:17:39 wuftpd Exp $
     31 
     32 ****************************************************************************/
     33 #include "config.h"
     34 
     35 #ifndef NO_PRIVATE
     36 
     37 #include <stdio.h>
     38 #include <errno.h>
     39 
     40 extern char *strsep(char **, const char *);
     41 
     42 #include <string.h>
     43 #ifdef HAVE_SYS_SYSLOG_H
     44 #include <sys/syslog.h>
     45 #endif
     46 #if defined(HAVE_SYSLOG_H) || (!defined(AUTOCONF) && !defined(HAVE_SYS_SYSLOG_H))
     47 #include <syslog.h>
     48 #endif
     49 #include <grp.h>
     50 
     51 #include <sys/types.h>
     52 #include <sys/stat.h>
     53 #include <sys/file.h>
     54 
     55 #ifdef HAVE_PATHS_H
     56 #include <paths.h>
     57 #endif
     58 #include "pathnames.h"
     59 #include "extensions.h"
     60 #include "proto.h"
     61 
     62 #ifdef SECUREOSF
     63 #define SecureWare		/* Does this mean it works for all SecureWare? */
     64 #endif
     65 
     66 #ifdef HPUX_10_TRUSTED
     67 #include <hpsecurity.h>
     68 #endif
     69 
     70 #if defined(SecureWare) || defined(HPUX_10_TRUSTED)
     71 #include <prot.h>
     72 #endif
     73 
     74 #ifndef NO_CRYPT_PROTO
     75 extern char *crypt(const char *, const char *);
     76 #endif
     77 
     78 static int group_attempts, group_given;
     79 static char *groupname, *passbuf;
     80 
     81 struct acgrp {
     82     char *gname;		/* access group name */
     83     char *gpass;		/* access group password */
     84     gid_t gr_gid;		/* group to setegid() to */
     85     struct acgrp *next;
     86 };
     87 
     88 static struct acgrp *privptr, *privtail;
     89 
     90 extern int lgi_failure_threshold;
     91 extern char remoteident[];
     92 
     93 static void add_acgrp(char *gname, char *gpass, gid_t gid)
     94 {
     95     struct acgrp *aptr;
     96 
     97     aptr = (struct acgrp *) calloc(1, sizeof(struct acgrp));
     98     if (aptr == NULL) {
     99 	syslog(LOG_ERR, "calloc error in add_acgrp");
    100 	dologout(1);
    101     }
    102 
    103     /* add element to end of list */
    104     if (privtail)
    105 	privtail->next = aptr;
    106     privtail = aptr;
    107     if (!privptr)
    108 	privptr = aptr;
    109 
    110     aptr->gname = strdup(gname);
    111     if (aptr->gname == NULL) {
    112 	syslog(LOG_ERR, "malloc error in add_acgrp");
    113 	dologout(1);
    114     }
    115     if (gpass == NULL)
    116 	aptr->gpass = strdup("");
    117     else
    118 	aptr->gpass = strdup(gpass);
    119     if (aptr->gpass == NULL) {
    120 	syslog(LOG_ERR, "malloc error in add_acgrp");
    121 	dologout(1);
    122     }
    123     aptr->gr_gid = gid;
    124 }
    125 
    126 static void parsepriv(void)
    127 {
    128     char *ptr;
    129     char *acptr = passbuf, *line;
    130     char *argv[3], *p, *val;
    131     struct group *gr;
    132     int n;
    133 
    134     if (!passbuf || !(*passbuf))
    135 	return;
    136 
    137     /* read through passbuf, stripping comments. */
    138     while (*acptr != '\0') {
    139 	line = acptr;
    140 	while (*acptr && *acptr != '\n')
    141 	    acptr++;
    142 	*acptr++ = '\0';
    143 
    144 	/* deal with comments */
    145 	if ((ptr = strchr(line, '#')) != NULL)
    146 	    *ptr = '\0';
    147 
    148 	if (*line == '\0')
    149 	    continue;
    150 
    151 	/* parse the lines... */
    152 	for (n = 0, p = line; n < 3 && p != NULL; n++) {
    153 	    val = (char *) strsep(&p, ":\n");
    154 	    argv[n] = val;
    155 	    if ((argv[n][0] == ' ') || (argv[n][0] == '\0'))
    156 		argv[n] = NULL;
    157 	}
    158 	/* check their were 3 fields, if not skip the line... */
    159 	if (n != 3 || p != NULL)
    160 	    continue;
    161 
    162 	if (argv[0] && argv[2]) {
    163 	    if (argv[2][0] == '%') {
    164 		gid_t gid = atoi(argv[2] + 1);
    165 		if ((gr = getgrgid(gid)) != NULL)
    166 		    add_acgrp(argv[0], argv[1], gid);
    167 	    }
    168 	    else {
    169 		if ((gr = getgrnam((char *) argv[2])) != NULL)
    170 		    add_acgrp(argv[0], argv[1], gr->gr_gid);
    171 	    }
    172 	    endgrent();
    173 	}
    174     }
    175 }
    176 
    177 /*************************************************************************/
    178 /* FUNCTION  : priv_setup                                                */
    179 /* PURPOSE   : Set things up to use the private access password file.    */
    180 /* ARGUMENTS : path, the path to the private access password file        */
    181 /*************************************************************************/
    182 
    183 void priv_setup(char *path)
    184 {
    185     FILE *prvfile;
    186     struct stat finfo;
    187     struct acgrp *aptr;
    188 
    189     while (privptr) {
    190 	aptr = privptr->next;
    191 	free(privptr->gname);
    192 	free(privptr->gpass);
    193 	free(privptr);
    194 	privptr = aptr;
    195     }
    196     privtail = NULL;
    197 
    198     if (passbuf) {
    199 	free(passbuf);
    200 	passbuf = NULL;
    201     }
    202 
    203     if ((prvfile = fopen(path, "r")) == NULL) {
    204 	if (errno != ENOENT)
    205 	    syslog(LOG_ERR, "cannot open private access file %s: %s",
    206 		   path, strerror(errno));
    207 	return;
    208     }
    209     if (fstat(fileno(prvfile), &finfo) != 0) {
    210 	syslog(LOG_ERR, "cannot fstat private access file %s: %s", path,
    211 	       strerror(errno));
    212 	(void) fclose(prvfile);
    213 	return;
    214     }
    215     if (finfo.st_size == 0) {
    216 	passbuf = (char *) calloc(1, 1);
    217     }
    218     else {
    219 	if (!(passbuf = (char *) malloc((size_t) finfo.st_size + 1))) {
    220 	    (void) syslog(LOG_ERR, "could not malloc passbuf (%d bytes)",
    221 			  (size_t) finfo.st_size + 1);
    222 	    (void) fclose(prvfile);
    223 	    return;
    224 	}
    225 	if (!fread(passbuf, (size_t) finfo.st_size, 1, prvfile)) {
    226 	    (void) syslog(LOG_ERR, "error reading private access file %s: %s",
    227 			  path, strerror(errno));
    228 	    (void) fclose(prvfile);
    229 	    return;
    230 	}
    231 	*(passbuf + finfo.st_size) = '\0';
    232     }
    233     (void) fclose(prvfile);
    234     (void) parsepriv();
    235 }
    236 
    237 /*************************************************************************/
    238 /* FUNCTION  : priv_getent                                               */
    239 /* PURPOSE   : Retrieve an entry from the in-memory copy of the group    */
    240 /* access file.                                              */
    241 /* ARGUMENTS : pointer to group name                                     */
    242 /*************************************************************************/
    243 
    244 static struct acgrp *priv_getent(char *group)
    245 {
    246     struct acgrp *ptr;
    247 
    248     for (ptr = privptr; ptr; ptr = ptr->next)
    249 	if (!strcasecmp(group, ptr->gname))
    250 	    return (ptr);
    251 
    252     return (NULL);
    253 }
    254 
    255 /*************************************************************************/
    256 /* FUNCTION  : priv_group                                                */
    257 /* PURPOSE   :                                                           */
    258 /* ARGUMENTS :                                                           */
    259 /*************************************************************************/
    260 
    261 void priv_group(char *group)
    262 {
    263     if (groupname)
    264 	free(groupname);
    265 
    266     groupname = strdup(group);
    267     if (groupname == NULL) {
    268 	reply(421, "Local resource failure: malloc");
    269 	syslog(LOG_ERR, "malloc error in priv_group");
    270 	dologout(1);
    271     }
    272     group_given = 1;
    273     reply(200, "Request for access to group %s accepted.", group);
    274 }
    275 
    276 /*************************************************************************/
    277 /* FUNCTION  : priv_gpass                                                */
    278 /* PURPOSE   : validate the group access request, and if OK place user   */
    279 /* in the proper group.                                      */
    280 /* ARGUMENTS : group access password                                     */
    281 /*************************************************************************/
    282 
    283 void priv_gpass(char *gpass)
    284 {
    285     char *xgpass = NULL;
    286     struct acgrp *grp;
    287     uid_t uid;
    288 
    289     if (group_given == 0) {
    290 	reply(503, "Give group name with SITE GROUP first.");
    291 	return;
    292     }
    293     /* OK, now they're getting a chance to specify a password.  Make them
    294      * give the group name again if they fail... */
    295     group_given = 0;
    296 
    297     grp = priv_getent(groupname);
    298     if (passbuf && gpass && *gpass != '\0' && grp && *grp->gpass != '\0')
    299 #if defined(SecureWare) || defined(HPUX_10_TRUSTED)
    300 	xgpass = bigcrypt(gpass, grp->gpass);
    301 #else
    302 	xgpass = crypt(gpass, grp->gpass);
    303 #endif
    304 
    305     if (!(((gpass != NULL)
    306 	   && (*gpass != '\0')
    307 	   && (grp != NULL)
    308 	   && (*grp->gpass != '\0')
    309 	   && (strcmp(xgpass, grp->gpass) == 0))
    310 	  || (((gpass == NULL)
    311 	       || (*gpass == '\0'))
    312 	      && (grp != NULL)
    313 	      && (*grp->gpass == '\0'))
    314 	)) {
    315 	reply(530, "Group access request incorrect.");
    316 	grp = NULL;
    317 	if (++group_attempts >= lgi_failure_threshold) {
    318 	    syslog(LOG_NOTICE,
    319 		   "repeated group access failures from %s, group %s",
    320 		   remoteident, groupname);
    321 	    dologout(0);
    322 	}
    323 	sleep(group_attempts);	/* slow down password crackers */
    324 	return;
    325     }
    326 
    327     uid = geteuid();
    328     setid_priv_on(0);
    329     setegid(grp->gr_gid);
    330     setid_priv_off(uid);
    331 
    332     reply(200, "Group access enabled.");
    333     group_attempts = 0;
    334 }
    335 #endif /* !NO_PRIVATE */
    336