void kerberos4_is(Authenticator *ap, unsigned char *data, int cnt) { struct sockaddr_in addr; char realm[REALM_SZ]; char instance[INST_SZ]; int r; int addr_len; if (cnt-- < 1) return; switch (*data++) { case KRB_AUTH: if (krb_get_lrealm(realm, 1) != KSUCCESS) { Data(ap, KRB_REJECT, (void *)"No local V4 Realm.", -1); auth_finished(ap, AUTH_REJECT); if (auth_debug_mode) printf("No local realm\r\n"); return; } memmove(auth.dat, data, auth.length = cnt); if (auth_debug_mode) { printf("Got %d bytes of authentication data\r\n", cnt); printf("CK: %d:", kerberos4_cksum(auth.dat, auth.length)); printd(auth.dat, auth.length); printf("\r\n"); } k_getsockinst(0, instance, sizeof(instance)); addr_len = sizeof(addr); if(getpeername(0, (struct sockaddr *)&addr, &addr_len) < 0) { if(auth_debug_mode) printf("getpeername failed\r\n"); Data(ap, KRB_REJECT, "getpeername failed", -1); auth_finished(ap, AUTH_REJECT); return; } r = krb_rd_req(&auth, KRB_SERVICE_NAME, instance, addr.sin_addr.s_addr, &adat, ""); if (r) { if (auth_debug_mode) printf("Kerberos failed him as %s\r\n", name); Data(ap, KRB_REJECT, (void *)krb_get_err_text(r), -1); auth_finished(ap, AUTH_REJECT); return; } /* save the session key */ memmove(session_key, adat.session, sizeof(adat.session)); krb_kntoln(&adat, name); if (UserNameRequested && !kuserok(&adat, UserNameRequested)){ char ts[MAXPATHLEN]; struct passwd *pw = getpwnam(UserNameRequested); if(pw){ snprintf(ts, sizeof(ts), "%s%u", TKT_ROOT, (unsigned)pw->pw_uid); setenv("KRBTKFILE", ts, 1); } Data(ap, KRB_ACCEPT, NULL, 0); } else { char *msg; asprintf (&msg, "user `%s' is not authorized to " "login as `%s'", krb_unparse_name_long(adat.pname, adat.pinst, adat.prealm), UserNameRequested ? UserNameRequested : "<nobody>"); if (msg == NULL) Data(ap, KRB_REJECT, NULL, 0); else { Data(ap, KRB_REJECT, (void *)msg, -1); free(msg); } } auth_finished(ap, AUTH_USER); break; case KRB_CHALLENGE: #ifndef ENCRYPTION Data(ap, KRB_RESPONSE, NULL, 0); #else if(!VALIDKEY(session_key)){ Data(ap, KRB_RESPONSE, NULL, 0); break; } des_key_sched(&session_key, sched); { des_cblock d_block; int i; Session_Key skey; memmove(d_block, data, sizeof(d_block)); /* make a session key for encryption */ des_ecb_encrypt(&d_block, &session_key, sched, 1); skey.type=SK_DES; skey.length=8; skey.data=session_key; encrypt_session_key(&skey, 1); /* decrypt challenge, add one and encrypt it */ des_ecb_encrypt(&d_block, &challenge, sched, 0); for (i = 7; i >= 0; i--) if(++challenge[i] != 0) break; des_ecb_encrypt(&challenge, &challenge, sched, 1); Data(ap, KRB_RESPONSE, (void *)challenge, sizeof(challenge)); } #endif break; case KRB_FORWARD: { des_key_schedule ks; unsigned char netcred[sizeof(CREDENTIALS)]; CREDENTIALS cred; int ret; if(cnt > sizeof(cred)) abort(); des_set_key(&session_key, ks); des_pcbc_encrypt((void*)data, (void*)netcred, cnt, ks, &session_key, DES_DECRYPT); unpack_cred(netcred, cnt, &cred); { if(strcmp(cred.service, KRB_TICKET_GRANTING_TICKET) || strncmp(cred.instance, cred.realm, sizeof(cred.instance)) || cred.lifetime < 0 || cred.lifetime > 255 || cred.kvno < 0 || cred.kvno > 255 || cred.issue_date < 0 || cred.issue_date > time(0) + CLOCK_SKEW || strncmp(cred.pname, adat.pname, sizeof(cred.pname)) || strncmp(cred.pinst, adat.pinst, sizeof(cred.pname))){ Data(ap, KRB_FORWARD_REJECT, "Bad credentials", -1); }else{ if((ret = tf_setup(&cred, cred.pname, cred.pinst)) == KSUCCESS){ struct passwd *pw = getpwnam(UserNameRequested); if (pw) chown(tkt_string(), pw->pw_uid, pw->pw_gid); Data(ap, KRB_FORWARD_ACCEPT, 0, 0); } else{ Data(ap, KRB_FORWARD_REJECT, krb_get_err_text(ret), -1); } } } memset(data, 0, cnt); memset(ks, 0, sizeof(ks)); memset(&cred, 0, sizeof(cred)); } break; default: if (auth_debug_mode) printf("Unknown Kerberos option %d\r\n", data[-1]); Data(ap, KRB_REJECT, 0, 0); break; } }
int listener::auth(int client_sock, uid_t *uid_out, gid_t *gid_out, char *complete_name, int namelen #ifdef USE_KRB , unsigned long ttime, // time ticket issued C_Block *sessionkey #endif ) { FUNC(listener::auth); c_uid_t uid; int remoteness=::same_process; #ifdef DEBUG dumpaddrs(client_sock, "listener::run"); #endif (void) max_sock_opt(client_sock, SO_RCVBUF); get_remoteness(client_sock, remoteness); #ifdef USE_KRB { // KERBEROS AUTHENTICATION /* specific to RPC 4.0 */ /* grot */ int krb_status; KTEXT_ST ticket; AUTH_DAT auth_data; char version[20]; Key_schedule sched; INSTANCE inst; struct sockaddr_in peer, me; // instance = '*' means authenticator will fill it in. memset(inst, '\0', sizeof(inst)); inst[0] = '*'; # ifdef MUTUAL # define kopt KOPT_DO_MUTUAL # else # define kopt 0 # endif krb_status = krb_recvauth(kopt, client_sock, &ticket, "rcmd", inst, &peer, &me, &auth_data, "" /* use /etc/srvtab */, sched, version); if(krb_status != KSUCCESS) { ShoreVasLayer.client_service->log->log(log_error, "Kerberos error %s ", (char *)krb_err_txt[krb_status]); return ::error_remoteness; } // who's it from? uid = (c_uid_t) SVAS_OK; if (krb_kntoln(&auth_data, complete_name) != KSUCCESS) { strcpy(complete_name, "*No local name returned by krb_kntoln*"); ShoreVasLayer.client_service->log->log(log_error, "Kerberos error %s ", (char *)krb_err_txt[krb_status]); return ::error_remoteness; } # ifdef DEBUG // print the info filled in by krb DBG( << "KRB connect: version " << version << "client krb-connect OK" ) # endif dassert(strcmp(auth_data.pname,complete_name)==0); } ttime = auth_data.time_sec, *sessionkey = auth_data.session; #else // NO KERBEROS: just read name and return uid { int cc; if( (cc = ::read(client_sock, complete_name, namelen)) <0) { // TODO: Shouldn't this use log instead of perror? perror("read login complete_name"); return ::error_remoteness; } complete_name[cc]='\0'; } #endif /* NO KERBEROS */ { *uid_out = uid = uname2uid(complete_name, gid_out); if(uid==BAD_UID) { DBG(<<"NO SUCH USER!"); ShoreVasLayer.client_service-> log->log(log_error, "Authentication error: no such user: %s", complete_name); return ::error_remoteness; } }