/******************************************************************** * $Author: jgoerzen $ * $Revision: 1.4 $ * $Date: 2002/01/08 18:03:25 $ * $Source: /var/cvs/gopher/gopherd/AUTH.c,v $ * * Paul Lindner, University of Minnesota DCS. * * Copyright 1991, 92, 93, 94 by the Regents of the University of Minnesota * see the file "Copyright" in the distribution for conditions of use. ********************************************************************* * MODULE: AUTH.c * Routines to verify authentication ********************************************************************* * Revision History: * $Log: AUTH.c,v $ * Revision 1.4 2002/01/08 18:03:25 jgoerzen * AUTH.c: add missing include of GGroup.h * * Revision 1.3 2001/01/17 19:30:25 jgoerzen * Change many sprintf -> snprintf * * Revision 1.2 2000/12/20 01:19:20 jgoerzen * Added patches from David Allen * * Revision 1.1.1.1 2000/08/19 00:28:56 jgoerzen * Import from UMN Gopher 2.3.1 after GPLization * * Revision 3.17 1995/10/31 16:54:28 lindner * Fix for checking for a group * * Revision 3.16 1995/09/25 05:02:28 lindner * Convert to ANSI C * * Revision 3.15 1995/06/30 20:33:08 lindner * Add group authentication * * Revision 3.14 1995/06/02 17:24:36 lindner * Add the ability to specify alternate password files for unixfile auth. * * Revision 3.13 1995/02/06 21:25:13 lindner * Better stdio include * * Revision 3.12 1995/02/02 17:13:52 lindner * Fix memory leaks * * Revision 3.11 1994/12/31 07:45:22 lindner * Remove Item is protected note * * Revision 3.10 1994/12/15 17:32:21 lindner * Fix for A/UX and undefined FILE*, AIX uses compat fgetpwent routines now * * Revision 3.9 1994/12/12 18:19:07 lindner * Fix aix hack * * Revision 3.8 1994/12/12 17:41:08 lindner * Hack around AIX * * Revision 3.7 1994/12/12 16:58:47 lindner * Use fgetpwent() instead of setpwfile() * * Revision 3.6 1994/12/10 06:12:13 lindner * Add support for a custom passwd file just for the gopher server * * Revision 3.5 1994/10/13 05:17:46 lindner * Compiler complaint fixes * * Revision 3.4 1994/07/22 22:27:20 lindner * NO_AUTHENTICATION mods * * Revision 3.3 1994/07/21 15:45:34 lindner * Fix for systems without unistd.h * * Revision 3.2 1994/07/03 21:18:11 lindner * Add initgroup() call * * Revision 3.1 1994/06/29 05:34:19 lindner * New authentication routines * * *********************************************************************/ #ifndef NO_AUTHENTICATION #include "AUTH.h" #include "compatible.h" #include "Regex.h" #include "Malloc.h" #include "fileio.h" /* For running scripts */ #include "String.h" /* strchr and friends */ #include "Debug.h" #include "GGroup.h" #include #ifndef VMS # include #endif AUTH* AUTHnew() { AUTH* temp; temp = (AUTH*) malloc(sizeof(AUTH)); temp->type = AUTH_UNINITED; temp->name = STRnew(); temp->scriptname = STRnew(); temp->authfcn = NULL; temp->authfcnask = NULL; return(temp); } void AUTHdestroy(AUTH *auth) { if (auth->name) STRdestroy(auth->name); if (auth->scriptname) STRdestroy(auth->scriptname); free(auth); } void AUTHinit(AUTH *auth) { STRinit(auth->name); STRinit(auth->scriptname); auth->authfcn = NULL; auth->authfcnask = NULL; auth->type = AUTH_UNINITED; } AUTH* AUTHcpy(AUTH *dest, AUTH *orig) { STRcpy(dest->name, orig->name); STRcpy(dest->scriptname, orig->scriptname); dest->authfcn = orig->authfcn; dest->authfcnask = orig->authfcnask; dest->type = orig->type; return(dest); } /* * A very generic ASK block */ char** AUTHgenericAsk(char *directory, char *defuser, char *defpw) { static char **Askstorage = NULL; Debug("Trying to do the generic ask block for %s\n", directory); if (Askstorage == NULL) { Askstorage = (char**)malloc(sizeof(char*)*5); Askstorage[0] = (char*) malloc(sizeof(char) * 80); Askstorage[1] = (char*) malloc(sizeof(char) * 80); Askstorage[2] = (char*) malloc(sizeof(char) * 80); Askstorage[3] = NULL; } if (defuser == NULL) defuser = ""; if (defpw == NULL) defpw = ""; /* if (directory == NULL) strcpy(Askstorage[0], "Note: This item is protected"); else sprintf(Askstorage[0], "Note: The item %s is protected", directory); */ sprintf(Askstorage[1], "Ask: Your User Name:\t%s", defuser); sprintf(Askstorage[2], "AskP: Your Password:\t%s", defpw); return(Askstorage); } /* * Check to see if 'password' is the users password. */ static AUTHresult AUTHunix_checkuser(struct passwd *pw, char *password) { char salt[3]; char *encodedpw; if (password == NULL) return(AUTHRES_OK); /* Group check, gack! */ strncpy(salt, pw->pw_passwd, 2); encodedpw = (char*) crypt(password, salt); if (strcmp(encodedpw, pw->pw_passwd) == 0) { if (getuid() == 0) { initgroups(pw->pw_name, pw->pw_gid); setuid(pw->pw_uid); setgid(pw->pw_gid); } return(AUTHRES_OK); } return(AUTHRES_BADPW); } /* * Use the password file in etc/passwd or specified in gopherd.conf * in the gopher-data directory to authenticate users. * Also check the groups file */ AUTHresult AUTHunixfile(AUTH *auth, char *username, char *password, char *hostname, char *hostip, char *extra_args) { #if !defined(VMS) char *pwfilename = "etc/passwd"; FILE *ourpasswd; struct passwd *pw; char *groups = NULL, *cp; AUTHresult pwcheck, groupresult; Debug("Trying to authenticate %s\n", username); if (extra_args != NULL) { /** First arg is password file, second is the list of groups **/ pwfilename = extra_args; cp = strchr(pwfilename, ' '); if (cp != NULL){ *cp = '\0'; groups = cp+1; } } if (password == NULL) { /** Just check the groups and get outta here... **/ if (groups != NULL) { /** Now test if the user is in any of the specified groups **/ do { cp = strchr(groups, ','); if (cp != NULL) *cp = '\0'; groupresult = GGTtest(groups, username); if (groupresult == AUTHRES_OK) return(groupresult); if (cp != NULL) groups = cp+1; } while (cp != NULL); return(AUTHRES_NOGROUP); } return(AUTHRES_OK); ; } ourpasswd = fopen(pwfilename, "r"); if (ourpasswd == NULL) { Debug("Couldn't open password file\n", pwfilename); return(AUTHRES_SYSERR); } if (fgetpwent(ourpasswd) == NULL) { Debugmsg("fgetpwent failed..."); return(AUTHRES_SYSERR); } fseek(ourpasswd, 0L,SEEK_SET); /** Mimic getpwnam, sigh why isn't setpwfile() everywhere....**/ while ((pw = fgetpwent(ourpasswd)) != NULL) { if (strcmp(pw->pw_name, username) == 0) { pwcheck = AUTHunix_checkuser(pw, password); if (groups != NULL && pwcheck == AUTHRES_OK) { /** Now test if the user is in any of the specified groups **/ do { cp = strchr(groups, ','); if (cp != NULL) *cp = '\0'; groupresult = GGTtest(groups, username); if (groupresult == AUTHRES_OK) return(groupresult); if (cp != NULL) groups = cp+1; } while (cp != NULL); return(AUTHRES_NOGROUP); } else return(pwcheck); } } return(AUTHRES_NOUSER); #else return(AUTHRES_SYSERR); #endif /*vms*/ } /* * Do the unix style /etc/passwd authentication... */ AUTHresult AUTHunix(AUTH *auth, char *username, char *password, char *hostname, char *hostip, char *extra_args) { #ifndef VMS struct passwd *pw; pw = getpwnam(username); if (pw == NULL) return(AUTHRES_NOUSER); return(AUTHunix_checkuser(pw, password)); #else return(AUTHRES_SYSERR) #endif /*VMS*/ } AUTHresult AUTHvalidate(AUTH *auth, char *username, char *password, char *hostname, char *hostip, char *extra_args) { int result; char *envstr; switch (AUTHgetType(auth)) { case AUTH_SCRIPT: /* * Need to set environment variables here... * note envstr must be malloced. */ envstr = (char*) malloc(sizeof(char) * (16+strlen(username))); sprintf(envstr, "GOPHER_USER=%s", username); putenv(envstr); free(envstr); envstr = (char*) malloc(sizeof(char) * (16+strlen(password))); sprintf(envstr, "GOPHER_PW=%s", password); putenv(envstr); free(envstr); envstr = (char*) malloc(sizeof(char) * (16+strlen(hostname))); sprintf(envstr, "GOPHER_HOST=%s", hostname); putenv(envstr); free(envstr); envstr = (char*) malloc(sizeof(char) * (16+strlen(hostip))); sprintf(envstr, "GOPHER_IP=%s", hostip); putenv(envstr); free(envstr); result = FIOsystem(AUTHgetScriptName(auth)); switch (result) { case 0: return(AUTHRES_OK); case 1: return(AUTHRES_BADPW); case 2: return(AUTHRES_EXPIRED); case 3: return(AUTHRES_NOUSER); default: return(AUTHRES_BADPW); } break; case AUTH_INTERNAL: return(auth->authfcn(auth, username, password, hostname, hostip, extra_args)); case AUTH_UNINITED: return(AUTHRES_BADPW); } return(AUTHRES_OK); } /************************************************************************* * AUTH array routines (AUTHA) */ AUTHarray* AUTHAnew(int size) { AUTHarray *aa; AUTH *auth; aa = DAnew((size),AUTHnew,AUTHinit,AUTHdestroy,AUTHcpy); auth = AUTHnew(); if (auth == NULL) return(NULL); /** Always supply some defaults... **/ AUTHsetType(auth, AUTH_INTERNAL); AUTHsetName(auth, "unix"); AUTHsetFcn(auth, AUTHunix); AUTHsetAskFcn(auth, AUTHgenericAsk); AUTHApush(aa, auth); AUTHsetType(auth, AUTH_INTERNAL); AUTHsetName(auth, "unixfile"); AUTHsetFcn(auth, AUTHunixfile); AUTHsetAskFcn(auth, AUTHgenericAsk); AUTHApush(aa, auth); AUTHdestroy(auth); return(aa); } /* * Process a gopherd.conf style line and add it to the array * really only for scripts. */ boolean AUTHAprocessLine(AUTHarray *autharr, char *inputline) { AUTH *auth; char *cp; auth = AUTHnew(); if (auth == NULL) return(FALSE); cp = strchr(inputline, ' '); *cp = '\0'; cp++; AUTHsetType(auth, AUTH_SCRIPT); AUTHsetScriptName(auth, cp); AUTHsetName(auth,inputline); AUTHsetAskFcn(auth, AUTHgenericAsk); AUTHApush(autharr, auth); AUTHdestroy(auth); return(TRUE); } /* * Find the authentication method, and pass the information to the * routine that handles it. */ AUTHresult AUTHAvalidate(AUTHarray *autha, char *type, char *username, char *password, char *hostname, char *hostip, char *extra_args) { int i; AUTH *auth; if (type == NULL) return(AUTHRES_BADPW); for (i=0; i < AUTHAgetTop(autha); i++) { auth = AUTHAgetEntry(autha, i); if (strcasecmp(type, AUTHgetName(auth)) == 0) { return(AUTHvalidate(auth,username,password,hostname,hostip,extra_args)); } } /** Shouldn't get to here.. **/ return(AUTHRES_BADPW); } /* * Find an AUTH item in the autha array */ AUTH* AUTHAlocate(AUTHarray *autha, char *type) { int i; AUTH *auth; if (type == NULL) return(NULL); for (i=0; i < AUTHAgetTop(autha); i++) { auth = AUTHAgetEntry(autha, i); if (strcasecmp(type, AUTHgetName(auth)) == 0) { return(auth); } } /** Shouldn't get to here.. **/ return(NULL); } /********************************************************************* * AUTHITEMS array */ #include "Regex.h" AUTHITEMS * AUTHITEMSnew(int size) { AUTHITEMS *ai; ai = (AUTHITEMS*) malloc(sizeof(AUTHITEMS)); if (ai != NULL) { ai->regexps = STAnew(size); ai->authtypes = STAnew(size); ai->extra_args = STAnew(size); } return(ai); } void AUTHITEMSdestroy(AUTHITEMS *ai) { if (ai == NULL) return; STAdestroy(ai->regexps); STAdestroy(ai->authtypes); STAdestroy(ai->extra_args); } void AUTHITEMSpush(AUTHITEMS *ai, char *regexp, char *authtype, char *extra_args) { String *str; if (ai == NULL) return; str = STRnew(); if (str == NULL) return; STRset(str, regexp); STApush(ai->regexps, str); STRset(str, authtype); STApush(ai->authtypes, str); STRset(str, extra_args); STApush(ai->extra_args, str); STRdestroy(str); } /* * Find a match for the item in the regular expressions * * returns NULL if no match found.. */ char * AUTHITEMSfindType(AUTHITEMS *ai, char *fname) { int i; char *rexp; if (ai == NULL) return(NULL); for (i=0; i < STAgetTop(ai->regexps); i++) { rexp = STAgetText(ai->regexps, i); if (re_comp(rexp)) return(NULL); if (re_exec(fname) == 1) { /* We have a match */ return(STAgetText(ai->authtypes, i)); } } return(NULL); /* No match found.. */ } char * AUTHITEMSfindExtraArgs(AUTHITEMS *ai, char *fname) { int i; char *rexp; if (ai == NULL) return(NULL); for (i=0; i < STAgetTop(ai->regexps); i++) { rexp = STAgetText(ai->regexps, i); if (re_comp(rexp)) return(NULL); if (re_exec(fname) == 1) { /* We have a match */ return(STAgetText(ai->extra_args, i)); } } return(NULL); /* No match found.. */ } /* * Find the auth item required.. */ AUTH* AUTHITEMSfindAUTH(AUTHITEMS *ai, AUTHarray *aa, char *fname) { int i; char *rexp; if (ai == NULL) return(NULL); for (i=0; i < STAgetTop(ai->regexps); i++) { rexp = STAgetText(ai->regexps, i); Debug("Trying %s\n", rexp); if (re_comp(rexp)) return(NULL); if (re_exec(fname) == 1) { /* We have a match */ return(AUTHAlocate(aa, STAgetText(ai->authtypes, i))); } } return(NULL); /* No match found.. */ } /* * Process a gopherd.conf style line and put it into the arrays. */ boolean AUTHITEMSprocessLine(AUTHITEMS *ai, char *inputline) { char *regex = NULL; char *extra_args = NULL; char *cp; regex = strchr(inputline, ' '); if (regex == NULL) return(FALSE); *regex = '\0'; regex++; cp = regex; if (*regex == '\'') { cp ++; while (*cp != '\'' && *cp != '\0') cp++; if (cp == '\0') cp = NULL; /* No extra args.. */ } else { cp = strchr(regex, ' '); } if (cp != NULL) { *cp = '\0'; extra_args = cp+1; } /* inputline is the type of authentication, cp+1 is the regexp and optional filename... */ AUTHITEMSpush(ai, regex, inputline, extra_args); return(TRUE); } #endif