X-Git-Url: http://andersk.mit.edu/gitweb/moira.git/blobdiff_plain/c1665e6d3ad5febe64ce64ad270587bdcab4307a..328f0c3db5770ce36a1f7f1b7c95af26d9683927:/server/mr_sauth.c diff --git a/server/mr_sauth.c b/server/mr_sauth.c index f3e08a21..52431de1 100644 --- a/server/mr_sauth.c +++ b/server/mr_sauth.c @@ -1,165 +1,184 @@ -/* - * $Source$ - * $Author$ - * $Header$ +/* $Id$ + * + * Handle server side of authentication * - * Copyright (C) 1987 by the Massachusetts Institute of Technology - * For copying and distribution information, please see the file - * . + * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology + * For copying and distribution information, please see the file + * . * */ -#ifndef lint -static char *rcsid_sms_sauth_c = "$Header$"; -#endif lint - #include -#include -#include "sms_server.h" -#include +#include "mr_server.h" + +#include + +#include +#include + +#include +#include + +RCSID("$Header$"); + +extern char *whoami, *host; +extern int proxy_acl; + +static int set_client(client *cl, char *kname, + char *name, char *inst, char *realm); -extern char buf1[]; -extern char *whoami; -extern char *malloc(); +typedef struct _replay_cache { + KTEXT_ST auth; + time_t expires; + struct _replay_cache *next; +} replay_cache; -char *kname_unparse(); +replay_cache *rcache = NULL; /* - * Handle a SMS_AUTH RPC request. + * Handle a MOIRA_AUTH RPC request. * * argv[0] is a kerberos authenticator. Decompose it, and if - * successful, store the name the user authenticated to in + * successful, store the name the user authenticated to in * cl->cl_name. */ -void -do_auth(cl) - client *cl; +void do_auth(client *cl) { - KTEXT_ST auth; - AUTH_DAT ad; - int status, ok; - char buf[REALM_SZ+INST_SZ+ANAME_SZ]; - - auth.length = cl->args->sms_argl[0]; - bcopy(cl->args->sms_argv[0], (char *)auth.dat, auth.length); - auth.mbz = 0; - - if ((status = krb_rd_req (&auth, "sms", "sms", cl->haddr.sin_addr, - &ad, "")) != 0) { - status += ERROR_TABLE_BASE_krb; - cl->reply.sms_status = status; - if (log_flags & LOG_RES) - com_err(whoami, status, "(authentication failed)"); - return; + KTEXT_ST auth; + AUTH_DAT ad; + int status; + replay_cache *rc, *rcnew; + time_t now; + + auth.length = cl->req.mr_argl[0]; + memcpy(auth.dat, cl->req.mr_argv[0], auth.length); + auth.mbz = 0; + + if ((status = krb_rd_req(&auth, MOIRA_SNAME, host, + cl->haddr.sin_addr.s_addr, &ad, ""))) + { + status += ERROR_TABLE_BASE_krb; + client_reply(cl, status); + com_err(whoami, status, " (authentication failed)"); + return; + } + + if (!rcache) + { + rcache = xmalloc(sizeof(replay_cache)); + memset(rcache, 0, sizeof(replay_cache)); + } + + /* scan replay cache */ + for (rc = rcache->next; rc; rc = rc->next) + { + if (auth.length == rc->auth.length && + !memcmp(&(auth.dat), &(rc->auth.dat), auth.length)) + { + com_err(whoami, 0, + "Authenticator replay from %s using authenticator for %s", + inet_ntoa(cl->haddr.sin_addr), + kname_unparse(ad.pname, ad.pinst, ad.prealm)); + com_err(whoami, KE_RD_AP_REPEAT, " (authentication failed)"); + client_reply(cl, KE_RD_AP_REPEAT); + return; } + } - bcopy(ad.pname, cl->kname.name, ANAME_SZ); - bcopy(ad.pinst, cl->kname.inst, INST_SZ); - bcopy(ad.prealm, cl->kname.realm, REALM_SZ); - strcpy(cl->clname, kname_unparse(ad.pname, ad.pinst, ad.prealm)); - - if (ad.pinst[0] == 0 && !strcmp(ad.prealm, krb_realm)) - ok = 1; - else - ok = 0; - /* this is in a separate function because it accesses the database */ - set_krb_mapping(cl->clname, ad.pname, ok, - &cl->client_id, &cl->users_id); - - if (cl->args->sms_version_no == SMS_VERSION_2) { - bcopy(cl->args->sms_argv[1], cl->entity, 8); - cl->entity[8] = 0; - } else { - strcpy(cl->entity, "???"); + /* add new entry */ + time(&now); + rcnew = xmalloc(sizeof(replay_cache)); + memcpy(&(rcnew->auth), &auth, sizeof(KTEXT_ST)); + rcnew->expires = now + 2 * CLOCK_SKEW; + rcnew->next = rcache->next; + rcache->next = rcnew; + + /* clean cache */ + for (rc = rcnew; rc->next; ) + { + if (rc->next->expires < now) + { + rcnew = rc->next; + rc->next = rc->next->next; + free(rcnew); } - bzero(&ad, sizeof(ad)); /* Clean up session key, etc. */ + else + rc = rc->next; + } - if (log_flags & LOG_RES) - com_err(whoami, 0, "Auth to %s using %s, uid %d cid %d", - cl->clname, cl->entity, cl->users_id, cl->client_id); - if (cl->users_id == 0) - cl->reply.sms_status = SMS_USER_AUTH; -} + status = set_client(cl, kname_unparse(ad.pname, ad.pinst, ad.prealm), + ad.pname, ad.pinst, ad.prealm); + strncpy(cl->entity, cl->req.mr_argv[1], sizeof(cl->entity) - 1); + cl->entity[sizeof(cl->entity) - 1] = 0; -/* Turn a principal, instance, realm triple into a single non-ambiguous - * string. This is the inverse of kname_parse(). It returns a pointer - * to a static buffer, or NULL on error. - */ + memset(&ad, 0, sizeof(ad)); /* Clean up session key, etc. */ + + com_err(whoami, 0, "Auth to %s using %s, uid %d cid %d", + cl->clname, cl->entity, cl->users_id, cl->client_id); + + if (status != MR_SUCCESS || cl->users_id != 0) + client_reply(cl, status); + else + client_reply(cl, MR_USER_AUTH); +} -char *kname_unparse(p, i, r) -char *p; -char *i; -char *r; +void do_proxy(client *cl) { - static char name[MAX_K_NAME_SZ]; - char *s; - - s = name; - if (!p || strlen(p) > ANAME_SZ) - return(NULL); - while (*p) { - switch (*p) { - case '@': - *s++ = '\\'; - *s++ = '@'; - break; - case '.': - *s++ = '\\'; - *s++ = '.'; - break; - case '\\': - *s++ = '\\'; - *s++ = '\\'; - break; - default: - *s++ = *p; - } - p++; + char name[ANAME_SZ], inst[INST_SZ], realm[REALM_SZ]; + char kname[MAX_K_NAME_SZ]; + + if (cl->proxy_id) + { + com_err(whoami, MR_PERM, "Cannot re-proxy"); + client_reply(cl, MR_PERM); + return; } - if (i && *i) { - if (strlen(i) > INST_SZ) - return(NULL); - *s++ = '.'; - while (*i) { - switch (*i) { - case '@': - *s++ = '\\'; - *s++ = '@'; - break; - case '.': - *s++ = '\\'; - *s++ = '.'; - break; - case '\\': - *s++ = '\\'; - *s++ = '\\'; - break; - default: - *s++ = *i; - } - i++; - } + + if (kname_parse(name, inst, realm, cl->req.mr_argv[0]) != KSUCCESS) + { + com_err(whoami, KE_KNAME_FMT, "while parsing proxy name %s", + cl->req.mr_argv); + client_reply(cl, KE_KNAME_FMT); + return; } - *s++ = '@'; - if (!r || strlen(r) > REALM_SZ) - return(NULL); - while (*r) { - switch (*r) { - case '@': - *s++ = '\\'; - *s++ = '@'; - break; - case '\\': - *s++ = '\\'; - *s++ = '\\'; - break; - default: - *s++ = *r; - } - r++; + + if (!*realm) + { + strcpy(realm, krb_realm); + sprintf(kname, "%s@%s", cl->req.mr_argv[0], realm); + } + else + strcpy(kname, cl->req.mr_argv[0]); + + if (find_member("LIST", proxy_acl, cl)) + { + cl->proxy_id = cl->client_id; + set_client(cl, kname, name, inst, realm); + com_err(whoami, 0, "Proxy authentication as %s (uid %d cid %d) via %s", + kname, cl->users_id, cl->client_id, cl->req.mr_argv[1]); + client_reply(cl, MR_SUCCESS); } - *s = '\0'; - return(&name[0]); + else + { + com_err(whoami, MR_PERM, "Proxy authentication denied"); + client_reply(cl, MR_PERM); + } +} + +static int set_client(client *cl, char *kname, + char *name, char *inst, char *realm) +{ + int ok; + + strncpy(cl->clname, kname, sizeof(cl->clname)); + cl->clname[sizeof(cl->clname) - 1] = '\0'; + + if (inst[0] == 0 && !strcmp(realm, krb_realm)) + ok = 1; + else + ok = 0; + /* this is in a separate function because it accesses the database */ + return set_krb_mapping(cl->clname, name, ok, &cl->client_id, &cl->users_id); }