/* auth.c for Shadowed Password systems. Submitted by . Replace the auth.c in etc/afpd in the source tree and compile with -DSHADOW_PASSWORD to get a version of afpd that will work with shadowed passwording. */ /* * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef SHADOW_PASSWORD #include #endif SHADOW_PASSWORD #include "auth.h" #include "globals.h" #include "switch.h" #if defined( KRB ) || defined( AFS ) || defined( UAM_AFSKRB ) #include #endif KRB AFS UAM_AFSKRB #if defined( KRB ) || defined( UAM_AFSKRB ) #include #include #include C_Block seskey; Key_schedule seskeysched; static char realm[ REALM_SZ ]; #endif KRB UAM_AFSKRB #ifdef UAM_AFSKRB static int validseskey = 0; static int logged = 0; static char *tktfile; static char instance[ INST_SZ ], name[ ANAME_SZ ]; #endif UAM_AFSKRB #ifdef AFS #include #include #include #include char *ka_LocalCell(); struct ClearToken { long AuthHandle; char HandShakeKey[8]; long ViceId; long BeginTimestamp; long EndTimestamp; }; #endif AFS int afp_version = 11; uid_t uuid; #if defined( sun ) || defined( ultrix ) int groups[ NGROUPS ]; #else sun ultrix gid_t groups[ NGROUPS ]; #endif sun ultrix int ngroups; char *username = NULL; char *mktemp(); /* * These numbers are scattered throughout the code. */ struct afp_versions afp_versions[] = { { "AFPVersion 1.1", 11 }, { "AFPVersion 2.0", 20 }, }; /* Note that these names must match those in main() */ struct afp_uams afp_uams[] = { #ifdef KRB { "Kerberos IV", krb4_login, krb4_logincont, 0 }, #else KRB { "Cleartxt passwrd", clrtxt_login, NULL, 0 }, #endif KRB #ifdef UAM_AFSKRB { "AFS Kerberos", afskrb_login, afskrb_logincont, 0 }, #endif UAM_AFSKRB { "No User Authent", noauth_login, NULL, 0 }, }; struct afp_uams *afp_uam = NULL; /* * Mark a UAM as off. */ uam_off( uam ) char *uam; { int i; for ( i = 0; i < sizeof( afp_uams ) / sizeof( afp_uams[ 0 ] ); i++ ) { if ( strcmp( uam, afp_uams[ i ].au_name ) == 0 ) { afp_uams[ i ].au_flags |= AU_OFF; return; } } return; } status_versions( data ) char *data; { struct afp_status *status; int len, num, i; status = (struct afp_status *)data; num = sizeof( afp_versions ) / sizeof( afp_versions[ 0 ] ); data += ntohs( status->as_versoff ); *data++ = num; for ( i = 0; i < num; i++ ) { len = strlen( afp_versions[ i ].av_name ); *data++ = len; bcopy( afp_versions[ i ].av_name , data, len ); data += len; } status->as_uamsoff = htons( data - (char *)status ); } status_uams( data ) char *data; { struct afp_status *status; int len, num, i; status = (struct afp_status *)data; for ( num = i = 0; i < sizeof( afp_uams ) / sizeof( afp_uams[ 0 ] ); i++ ) { if (( afp_uams[ i ].au_flags & AU_OFF ) == 0 ) { num++; } } data += ntohs( status->as_uamsoff ); *data++ = num; for ( i = 0; i < sizeof( afp_uams ) / sizeof( afp_uams[ 0 ] ); i++ ) { if (( afp_uams[ i ].au_flags & AU_OFF ) == 0 ) { len = strlen( afp_uams[ i ].au_name ); *data++ = len; bcopy( afp_uams[ i ].au_name, data, len ); data += len; } } status->as_iconoff = htons( data - (char *)status ); } afp_login( ibuf, ibuflen, rbuf, rbuflen ) char *ibuf, *rbuf; int ibuflen, *rbuflen; { int len, i, num; if ( nologin ) { *rbuflen = 0; return( AFPERR_SHUTDOWN ); } ibuf++; ibuflen--; len = *ibuf++; ibuflen--; num = sizeof( afp_versions ) / sizeof( afp_versions[ 0 ]); for ( i = 0; i < num; i++ ) { if ( strncmp( ibuf, afp_versions[ i ].av_name , len ) == 0 ) { afp_version = afp_versions[ i ].av_number; break; } } if ( i == num ) { /* An inappropo version */ *rbuflen = 0; return( AFPERR_BADVERS ); } ibuf += len; ibuflen -= len; len = *ibuf++; ibuflen--; num = sizeof( afp_uams ) / sizeof( afp_uams[ 0 ]); for ( i = 0; i < num; i++ ) { if ( afp_uams[ i ].au_flags & AU_OFF ) { continue; } if ( strncmp( ibuf, afp_uams[ i ].au_name, len ) == 0 ) { afp_uam = &afp_uams[ i ]; break; } } if ( i == num ) { *rbuflen = 0; return( AFPERR_BADUAM ); } ibuf += len; ibuflen -= len; *rbuflen = 0; return( afp_uam->au_login( ibuf, ibuflen, rbuf, rbuflen )); } afp_logincont( ibuf, ibuflen, rbuf, rbuflen, asp ) char *ibuf, *rbuf; int ibuflen, *rbuflen; ASP asp; { if ( afp_uam == NULL || afp_uam->au_logincont == NULL ) { *rbuflen = 0; return( AFPERR_NOTAUTH ); } return( afp_uam->au_logincont( ibuf, ibuflen, rbuf, rbuflen, asp )); } noauth_login( ibuf, ibuflen, rbuf, rbuflen ) char *ibuf, *rbuf; int ibuflen, *rbuflen; { struct passwd *pwent; *rbuflen = 0; syslog( LOG_INFO, "login noauth" ); /* this shit should be done by login() XXX */ if (( pwent = getpwnam( guest )) == NULL ) { syslog( LOG_ERR, "noauth_login: getpwname( %s ): %m", guest ); return( AFPERR_BADUAM ); } if ( setregid( pwent->pw_gid, pwent->pw_gid ) < 0 || setreuid( pwent->pw_uid, pwent->pw_uid ) < 0 ) { syslog( LOG_ERR, "noauth_login: setreugid: %m" ); return( AFPERR_BADUAM ); } uuid = pwent->pw_uid; ngroups = 0; #ifdef AFS if ( setpag() < 0 ) { syslog( LOG_ERR, "noauth_login: setpag: %m" ); return( AFPERR_BADUAM ); } #endif AFS afp_switch = postauth_switch; return( AFP_OK ); } login( name, uid, gid ) char *name; uid_t uid; gid_t gid; { if ( uid == 0 ) { /* don't allow root login */ syslog( LOG_ERR, "login: root login denied!" ); return( AFPERR_NOTAUTH ); } syslog( LOG_INFO, "login %s (uid %d, gid %d)", name, uid, gid ); if ( initgroups( name, gid ) < 0 || setregid( gid, gid ) < 0 || setreuid( uid, uid ) < 0 ) { syslog( LOG_ERR, "login: %m" ); return( AFPERR_BADUAM ); } if (( ngroups = getgroups( NGROUPS, groups )) < 0 ) { syslog( LOG_ERR, "login: getgroups: %m" ); return( AFPERR_BADUAM ); } uuid = uid; afp_switch = postauth_switch; return( AFP_OK ); } lcase( p ) char *p; { for (; *p; p++ ) { if ( isupper( *p )) { *p = tolower( *p ); } } return; } ucase( p ) char *p; { for (; *p; p++ ) { if ( islower( *p )) { *p = toupper( *p ); } } return; } #ifdef KRB #define KRB4CMD_HELO 1 #define KRB4RPL_REALM 2 #define KRB4WRT_SESS 3 #define KRB4RPL_DONE 4 #define KRB4RPL_PRINC 5 #define KRB4WRT_TOKEN 6 #define KRB4WRT_SKIP 7 #define KRB4RPL_DONEMUT 8 krb4_login( ibuf, ibuflen, rbuf, rbuflen ) char *ibuf, *rbuf; int ibuflen, *rbuflen; { char *p; int len; if ( *ibuf != KRB4CMD_HELO ) { *rbuflen = 0; syslog( LOG_INFO, "krb4_login: bad command %d", *ibuf ); return( AFPERR_NOTAUTH ); } p = rbuf; if ( krb_get_lrealm( realm, 1 ) != KSUCCESS ) { *rbuflen = 0; syslog( LOG_ERR, "krb4_login: can't get local realm!" ); return( AFPERR_NOTAUTH ); } *p++ = KRB4RPL_REALM; *p++ = 1; len = strlen( realm ); *p++ = len; strcpy( p, realm ); p += len + 1; #ifdef AFS if ( setpag() < 0 ) { *rbuflen = 0; syslog( LOG_ERR, "krb_login: setpag: %m" ); return( AFPERR_BADUAM ); } #endif AFS *rbuflen = p - rbuf; return( AFPERR_AUTHCONT ); } krb4_logincont( ibuf, ibuflen, rbuf, rbuflen, asp ) char *ibuf, *rbuf; int ibuflen, *rbuflen; ASP asp; { struct passwd *pwd; KTEXT_ST tkt; static AUTH_DAT ad; int rc; short len; char *p; CREDENTIALS cr; #ifdef AFS struct ViceIoctl vi; struct ClearToken ct; #endif AFS char buf[ 1024 ]; int aint; if ( asp_wrtcont( asp, rbuf, rbuflen ) < 0 ) { *rbuflen = 0; return( AFPERR_PARAM ); } p = rbuf; switch ( rc = *p++ ) { case KRB4WRT_SESS : bcopy( p, &len, sizeof( short )); tkt.length = ntohs( len ); p += sizeof( short ); if ( tkt.length <= 0 || tkt.length > MAX_KTXT_LEN ) { *rbuflen = 0; return( AFPERR_BADUAM ); } bcopy( p, tkt.dat, tkt.length ); p += tkt.length; if (( rc = krb_rd_req( &tkt, "afpserver", Obj, 0, &ad, "" )) != RD_AP_OK ) { syslog( LOG_ERR, "krb4_logincont: krb_rd_req: %s", krb_err_txt[ rc ] ); *rbuflen = 0; return( AFPERR_BADUAM ); } syslog( LOG_INFO, "krb4_login: %s.%s@%s", ad.pname, ad.pinst, ad.prealm ); bcopy( ad.session, seskey, sizeof( C_Block )); key_sched( seskey, seskeysched ); username = ad.pname; p = rbuf; #ifndef notdef *p = KRB4RPL_DONE; /* XXX */ *rbuflen = 1; if (( pwd = getpwnam( ad.pname )) == NULL ) { return( AFPERR_NOTAUTH ); } return( login( pwd->pw_name, pwd->pw_uid, pwd->pw_gid )); #else notdef /* get principals */ *p++ = KRB4RPL_PRINC; len = strlen( realm ); *p++ = len + 1; *p++ = '@'; strcpy( p, realm ); p += len + 1; *rbuflen = p - rbuf; return( AFPERR_AUTHCONT ); case KRB4WRT_TOKEN : bcopy( p, &len, sizeof( short )); len = ntohs( len ); syslog( LOG_DEBUG, "krb_logincont: cred %d sizeof %d", len, sizeof( cr )); p += sizeof( short ); bcopy( p, &cr, len ); syslog( LOG_DEBUG, "krb_logincont: prev %s.%s@%s", cr.service, cr.instance, cr.realm ); syslog( LOG_DEBUG, "krb_logincont: prev %d %d %d", cr.lifetime, cr.kvno, cr.issue_date ); syslog( LOG_DEBUG, "krb_logincont: prev %s %s", cr.pname, cr.pinst ); pcbc_encrypt((C_Block *)&cr, (C_Block *)&cr, len, seskeysched, seskey, DES_DECRYPT ); syslog( LOG_DEBUG, "krb_logincont: cred %s.%s@%s", cr.service, cr.instance, cr.realm ); syslog( LOG_DEBUG, "krb_logincont: cred %d %d %d", cr.lifetime, cr.kvno, cr.issue_date ); syslog( LOG_DEBUG, "krb_logincont: cred %s %s", cr.pname, cr.pinst ); p = buf; bcopy( &cr.ticket_st.length, p, sizeof( int )); p += sizeof( int ); bcopy( cr.ticket_st.dat, p, cr.ticket_st.length ); p += cr.ticket_st.length; ct.AuthHandle = cr.kvno; bcopy( cr.session, ct.HandShakeKey, sizeof( cr.session )); ct.ViceId = 0; ct.BeginTimestamp = cr.issue_date; ct.EndTimestamp = krb_life_to_time( cr.issue_date, cr.lifetime ); aint = sizeof( struct ClearToken ); bcopy( &aint, p, sizeof( int )); p += sizeof( int ); bcopy( &ct, p, sizeof( struct ClearToken )); p += sizeof( struct ClearToken ); aint = 0; bcopy( &aint, p, sizeof( int )); p += sizeof( int ); lcase( realm ); strcpy( p, realm ); p += strlen( realm ) + 1; vi.in = buf; vi.in_size = p - buf; vi.out = buf; vi.out_size = sizeof( buf ); if ( pioctl( 0, VIOCSETTOK, &vi, 0 ) < 0 ) { syslog( LOG_ERR, "krb4_logincont: pioctl: %m" ); *rbuflen = 0; return( AFPERR_BADUAM ); } syslog( LOG_INFO, "krb4_login: %s AFS", realm ); /* FALL THROUGH */ case KRB4WRT_SKIP : p = rbuf; *p = KRB4RPL_DONE; /* XXX */ *rbuflen = 1; if (( pwd = getpwnam( ad.pname )) == NULL ) { return( AFPERR_NOTAUTH ); } return( login( pwd->pw_name, pwd->pw_uid, pwd->pw_gid )); #endif notdef default : syslog( LOG_INFO, "krb4_logincont: bad command %d", rc ); *rbuflen = 0; return( AFPERR_NOTAUTH ); break; } } #else KRB extern char *crypt(); static char clrtxtname[ 31 ]; clrtxt_login( ibuf, ibuflen, rbuf, rbuflen ) char *ibuf, *rbuf; int ibuflen, *rbuflen; { #ifdef SHADOW_PASSWORD struct spwd *sp; #endif SHADOW_PASSWORD struct passwd *pwd; int len; char *p, *getusershell(); *rbuflen = 0; len = *ibuf++; if ( len > 31 ) { return( AFPERR_PARAM ); } bcopy( ibuf, clrtxtname, len ); ibuf += len; clrtxtname[ len ] = '\0'; username = clrtxtname; #ifdef SHADOW_PASSWORD if (( sp = (struct spwd *)getspnam( clrtxtname )) == (struct spwd *)0 ) { return( AFPERR_NOTAUTH ); } #endif SHADOW_PASSWORD if (( pwd = getpwnam( clrtxtname )) == NULL ) { return( AFPERR_NOTAUTH ); } if ( pwd->pw_shell != NULL && pwd->pw_shell[ 0 ] != NULL ) { while (( p = getusershell()) != NULL ) { if ( strcmp( p, pwd->pw_shell ) == 0 ) { break; } } endusershell(); if ( p == NULL ) { syslog( LOG_INFO, "illegal shell %s for %s", pwd->pw_shell, clrtxtname ); return( AFPERR_NOTAUTH ); } } #ifdef SHADOW_PASSWORD if ( sp->sp_pwdp != NULL ) { #else SHADOW_PASSWORD if ( pwd->pw_passwd != NULL ) { #endif SHADOW_PASSWORD if ( *ibuf == '\0' ) { ++ibuf; } #ifndef SHADOW_PASSWORD ibuf[ 8 ] = '\0'; #endif SHADOW_PASSWORD #ifdef AFS if ( kcheckuser( pwd, ibuf ) == 0 ) { return( login( pwd->pw_name, pwd->pw_uid, pwd->pw_gid )); } #endif AFS #ifdef SHADOW_PASSWORD p = crypt( ibuf, sp->sp_pwdp ); if ( strcmp( p, sp->sp_pwdp ) == 0 ) { #else SHADOW_PASSWORD p = crypt( ibuf, pwd->pw_passwd ); if ( strcmp( p, pwd->pw_passwd ) == 0 ) { #endif SHADOW_PASSWORD return( login( pwd->pw_name, pwd->pw_uid, pwd->pw_gid )); } } return( AFPERR_NOTAUTH ); } #ifdef AFS #include #include char *ka_LocalCell(); void addrealm(realm,cells) char *realm; char ***cells; { char **ptr; int temp; ptr= *cells; for(;*ptr != 0 ;ptr++) if(!strcmp(realm,*ptr)) return; temp=ptr- *cells; *cells=(char**)realloc(*cells,((2+temp)*sizeof(char*))); ptr= *cells+temp; *ptr=(char*)malloc(strlen(realm)+1); strcpy(*ptr++,realm); *ptr=0; return; } int kcheckuser(pwd,passwd) struct passwd *pwd; char *passwd; { long code; char *instance=""; char realm[MAXKTCREALMLEN]; char lorealm[MAXKTCREALMLEN]; char *cell; Date lifetime=MAXKTCTICKETLIFETIME; int rval; char **cells=(char **)malloc(sizeof(char*)); char *temp; int rc,cellNum; struct ktc_principal serviceName; *cells=0; code = ka_Init(0); { char *temp,*temp1; temp=(char*)malloc(strlen(pwd->pw_dir)+1); strcpy(temp,pwd->pw_dir); temp1=temp; temp=strtok(temp,"/"); temp=strtok('\0',"/"); ka_CellToRealm(temp,realm,0); addrealm(realm,&cells); free(temp1); } setpag(); authenticate(cells,pwd->pw_name,passwd); cellNum=0; rc=ktc_ListTokens(cellNum,&cellNum,&serviceName); if(rc) rval=1; else{ rval=0; } return(rval); } authenticate(cells,name,passwd) char **cells; char *name; char *passwd; { char **ptr=cells; char *errorstring; while(*ptr){ ka_UserAuthenticate(name,/*instance*/"",/*cell*/*ptr++, passwd,/*setpag*/0,&errorstring); } } #endif AFS #endif KRB #if defined( UAM_AFSKRB ) && defined( AFS ) afskrb_login( ibuf, ibuflen, rbuf, rbuflen ) char *ibuf, *rbuf; int ibuflen, *rbuflen; { KTEXT_ST authent, rpkt; CREDENTIALS cr; char *p, *q; int len, rc, whoserealm; short slen; len = *ibuf++; ibuf[ len ] = '\0'; if (( p = index( ibuf, '@' )) != NULL ) { *p++ = '\0'; strcpy( realm, p ); ucase( realm ); whoserealm = 0; } else { if ( krb_get_lrealm( realm, 1 ) != KSUCCESS ) { *rbuflen = 0; return( AFPERR_BADUAM ); } whoserealm = 1; } if (( p = index( ibuf, '.' )) != NULL ) { *p++ = '\0'; strcpy( instance, p ); } else { *instance = '\0'; } strcpy( name, ibuf ); /* * We don't have the session key, yet. Get one. */ p = rbuf; if ( validseskey == 0 ) { if ( setpag() < 0 ) { syslog( LOG_ERR, "krb_login: setpag: %m" ); *rbuflen = 0; return( AFPERR_BADUAM ); } krb_set_tkt_string(( tktfile = mktemp( _PATH_AFPTKT ))); if (( rc = krb_get_svc_in_tkt( "afpserver", Obj, realm, TICKET_GRANTING_TICKET, realm, 255, KEYFILE )) != INTK_OK ) { *rbuflen = 0; syslog( LOG_ERR, "krb_login: can't get ticket-granting-ticket" ); return(( whoserealm ) ? AFPERR_BADUAM : AFPERR_PARAM ); } if ( krb_mk_req( &authent, name, instance, realm, 0 ) != KSUCCESS ) { *rbuflen = 0; return( AFPERR_PARAM ); } if ( krb_get_cred( name, instance, realm, &cr ) != KSUCCESS ) { *rbuflen = 0; return( AFPERR_BADUAM ); } if ( unlink( tktfile ) < 0 ) { syslog( LOG_ERR, "krb_login: unlink %s: %m", tktfile ); *rbuflen = 0; return( AFPERR_BADUAM ); } bcopy( cr.session, seskey, sizeof( C_Block )); key_sched( seskey, seskeysched ); validseskey = 1; username = name; bcopy( authent.dat, p, authent.length ); p += authent.length; } if ( kuam_get_in_tkt( name, instance, realm, TICKET_GRANTING_TICKET, realm, 255, &rpkt ) != INTK_OK ) { *rbuflen = 0; return( AFPERR_PARAM ); } q = (char *)rpkt.dat; *p++ = *q++; *p++ = *q++; while ( *q++ ) ; while ( *q++ ) ; while ( *q++ ) ; q += 10; len = strlen( realm ); strcpy( p, realm ); p += len + 1; bcopy( q, &slen, sizeof( short )); bcopy( &slen, p, sizeof( short )); p += sizeof( short ); q += sizeof( short ); bcopy( q, p, slen ); p += slen; *rbuflen = p - rbuf; return( AFPERR_AUTHCONT ); } afskrb_logincont( ibuf, ibuflen, rbuf, rbuflen ) char *ibuf, *rbuf; int ibuflen, *rbuflen; { CREDENTIALS cr; struct ViceIoctl vi; struct ClearToken ct; struct passwd *pwd; char buf[ 1024 ], *p; int aint; short clen; *rbuflen = 0; ibuf += 2; bcopy( ibuf, &clen, sizeof( short )); clen = ntohs( clen ); ibuf += sizeof( short ); pcbc_encrypt((C_Block *)ibuf, (C_Block *)ibuf, clen, seskeysched, seskey, DES_DECRYPT ); if ( kuam_set_in_tkt( name, instance, realm, TICKET_GRANTING_TICKET, realm, ibuf ) != INTK_OK ) { return( AFPERR_PARAM ); } if ( get_ad_tkt( "afs", "", realm, 255 ) != KSUCCESS ) { return( AFPERR_PARAM ); } if ( krb_get_cred( "afs", "", realm, &cr ) != KSUCCESS ) { return( AFPERR_PARAM ); } p = buf; bcopy( &cr.ticket_st.length, p, sizeof( int )); p += sizeof( int ); bcopy( cr.ticket_st.dat, p, cr.ticket_st.length ); p += cr.ticket_st.length; ct.AuthHandle = cr.kvno; bcopy( cr.session, ct.HandShakeKey, sizeof( cr.session )); ct.ViceId = 0; ct.BeginTimestamp = cr.issue_date; /* ct.EndTimestamp = cr.issue_date + ( cr.lifetime * 5 * 60 ); */ ct.EndTimestamp = krb_life_to_time( cr.issue_date, cr.lifetime ); aint = sizeof( struct ClearToken ); bcopy( &aint, p, sizeof( int )); p += sizeof( int ); bcopy( &ct, p, sizeof( struct ClearToken )); p += sizeof( struct ClearToken ); aint = 0; bcopy( &aint, p, sizeof( int )); p += sizeof( int ); lcase( realm ); strcpy( p, realm ); p += strlen( realm ) + 1; vi.in = buf; vi.in_size = p - buf; vi.out = buf; vi.out_size = sizeof( buf ); if ( pioctl( 0, VIOCSETTOK, &vi, 0 ) < 0 ) { syslog( LOG_ERR, "krb_logincont: pioctl: %m" ); return( AFPERR_BADUAM ); } if ( unlink( tktfile ) < 0 ) { syslog( LOG_ERR, "krb_logincont: %s: %m", tktfile ); return( AFPERR_BADUAM ); } if (( pwd = getpwnam( username )) == NULL ) { return( AFPERR_NOTAUTH ); } if ( logged == 0 ) { logged = 1; syslog( LOG_INFO, "authenticated %s.%s@%s", name, instance, realm ); return( login( pwd->pw_name, pwd->pw_uid, pwd->pw_gid )); } syslog( LOG_INFO, "re-authenticated %s.%s@%s", name, instance, realm ); return( AFP_OK ); } #endif UAM_AFSKRB AFS