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 */