source: trunk/third/moira/server/mr_sauth.c @ 23740

Revision 23740, 6.6 KB checked in by broder, 15 years ago (diff)
In moira: * New CVS snapshot (Trac: #195) * Drop patches that have been incorporated upstream. * Update to build without krb4 on systems that no longer have it. This doesn't build yet on squeeze, which lacks a krb4 library, but I'm committing now before I start hacking away at a patch to fix that.
Line 
1/* $Id: mr_sauth.c,v 1.32 2007-05-08 16:25:28 zacheiss Exp $
2 *
3 * Handle server side of authentication
4 *
5 * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
6 * For copying and distribution information, please see the file
7 * <mit-copyright.h>.
8 *
9 */
10
11#include <mit-copyright.h>
12#include "mr_server.h"
13
14#include <sys/types.h>
15
16#include <arpa/inet.h>
17#include <netinet/in.h>
18
19#include <stdlib.h>
20#include <string.h>
21
22RCSID("$Header: /afs/athena.mit.edu/astaff/project/moiradev/repository/moira/server/mr_sauth.c,v 1.32 2007-05-08 16:25:28 zacheiss Exp $");
23
24extern char *whoami, *host;
25extern int proxy_acl;
26extern krb5_context context;
27
28static int set_client(client *cl, char *kname,
29                      char *name, char *inst, char *realm);
30
31typedef struct _replay_cache {
32  KTEXT_ST auth;
33  time_t expires;
34  struct _replay_cache *next;
35} replay_cache;
36
37replay_cache *rcache = NULL;
38
39/*
40 * Handle a MOIRA_AUTH RPC request.
41 *
42 * argv[0] is a kerberos authenticator.  Decompose it, and if
43 * successful, store the name the user authenticated to in
44 * cl->cl_name.
45 */
46
47void do_auth(client *cl)
48{
49  KTEXT_ST auth;
50  AUTH_DAT ad;
51  int status;
52  replay_cache *rc, *rcnew;
53  time_t now;
54
55  auth.length = cl->req.mr_argl[0];
56  memcpy(auth.dat, cl->req.mr_argv[0], auth.length);
57  auth.mbz = 0;
58
59  if ((status = krb_rd_req(&auth, MOIRA_SNAME, host,
60                           cl->haddr.sin_addr.s_addr, &ad, "")))
61    {
62      status += ERROR_TABLE_BASE_krb;
63      client_reply(cl, status);
64      com_err(whoami, status, " (authentication failed)");
65      return;
66    }
67
68  if (!rcache)
69    {
70      rcache = xmalloc(sizeof(replay_cache));
71      memset(rcache, 0, sizeof(replay_cache));
72    }
73
74  /* scan replay cache */
75  for (rc = rcache->next; rc; rc = rc->next)
76    {
77      if (auth.length == rc->auth.length &&
78          !memcmp(&(auth.dat), &(rc->auth.dat), auth.length))
79        {
80          com_err(whoami, 0,
81                  "Authenticator replay from %s using authenticator for %s",
82                  inet_ntoa(cl->haddr.sin_addr),
83                  mr_kname_unparse(ad.pname, ad.pinst, ad.prealm));
84          com_err(whoami, KE_RD_AP_REPEAT, " (authentication failed)");
85          client_reply(cl, KE_RD_AP_REPEAT);
86          return;
87        }
88    }
89
90  /* add new entry */
91  time(&now);
92  rcnew = xmalloc(sizeof(replay_cache));
93  memcpy(&(rcnew->auth), &auth, sizeof(KTEXT_ST));
94  rcnew->expires = now + 2 * CLOCK_SKEW;
95  rcnew->next = rcache->next;
96  rcache->next = rcnew;
97
98  /* clean cache */
99  for (rc = rcnew; rc->next; )
100    {
101      if (rc->next->expires < now)
102        {
103          rcnew = rc->next;
104          rc->next = rc->next->next;
105          free(rcnew);
106        }
107      else
108        rc = rc->next;
109    }
110
111  status = set_client(cl, mr_kname_unparse(ad.pname, ad.pinst, ad.prealm),
112                      ad.pname, ad.pinst, ad.prealm);
113
114  strncpy(cl->entity, cl->req.mr_argv[1], sizeof(cl->entity) - 1);
115  cl->entity[sizeof(cl->entity) - 1] = 0;
116
117  memset(&ad, 0, sizeof(ad));   /* Clean up session key, etc. */
118
119  com_err(whoami, 0, "Auth to %s using %s, uid %d cid %d",
120          cl->clname, cl->entity, cl->users_id, cl->client_id);
121
122  if (status != MR_SUCCESS || cl->users_id != 0)
123    client_reply(cl, status);
124  else
125    client_reply(cl, MR_USER_AUTH);
126}
127
128void do_proxy(client *cl)
129{
130  char name[ANAME_SZ] = "\0", inst[INST_SZ] = "\0", realm[REALM_SZ] = "\0";
131  char kname[MAX_K_NAME_SZ];
132
133  if (cl->proxy_id)
134    {
135      com_err(whoami, MR_PERM, "Cannot re-proxy");
136      client_reply(cl, MR_PERM);
137      return;
138    }
139
140  if (kname_parse(name, inst, realm, cl->req.mr_argv[0]) != KSUCCESS)
141    {
142      com_err(whoami, KE_KNAME_FMT, "while parsing proxy name %s",
143              cl->req.mr_argv);
144      client_reply(cl, KE_KNAME_FMT);
145      return;
146    }
147
148  if (!*realm)
149    {
150      strcpy(realm, krb_realm);
151      sprintf(kname, "%s@%s", cl->req.mr_argv[0], realm);
152    }
153  else
154    strcpy(kname, cl->req.mr_argv[0]);
155   
156  if (find_member("LIST", proxy_acl, cl))
157    {
158      cl->proxy_id = cl->client_id;
159      set_client(cl, kname, name, inst, realm);
160      com_err(whoami, 0, "Proxy authentication as %s (uid %d cid %d) via %s",
161              kname, cl->users_id, cl->client_id, cl->req.mr_argv[1]);
162      client_reply(cl, MR_SUCCESS);
163    }
164  else
165    {
166      com_err(whoami, MR_PERM, "Proxy authentication denied");
167      client_reply(cl, MR_PERM);
168    }
169}
170
171static int set_client(client *cl, char *kname,
172                      char *name, char *inst, char *realm)
173{
174  int ok;
175
176  strncpy(cl->clname, kname, sizeof(cl->clname));
177  cl->clname[sizeof(cl->clname) - 1] = '\0';
178
179  if ((!inst || inst[0] == 0) && !strcmp(realm, krb_realm))
180    ok = 1;
181  else
182    ok = 0;
183  /* this is in a separate function because it accesses the database */
184  return set_krb_mapping(cl->clname, name, ok, &cl->client_id, &cl->users_id);
185}
186
187void do_krb5_auth(client *cl)
188{
189  krb5_data auth;
190  krb5_auth_context auth_con = NULL;
191  krb5_principal server = NULL, client = NULL;
192  krb5_ticket *ticket;
193  char name[ANAME_SZ], inst[INST_SZ], realm[REALM_SZ];
194  int status;
195
196  ticket = NULL;
197
198  status = krb5_auth_con_init(context, &auth_con);
199  if (status)
200    {
201      client_reply(cl, status);
202      com_err(whoami, status, "(krb5 auth context init failed)");
203      goto out;
204    }
205
206  status = krb5_sname_to_principal(context, host, MOIRA_SNAME,
207                                    KRB5_NT_SRV_HST, &server);
208  if (status)
209    {
210      client_reply(cl, status);
211      com_err(whoami, status, "(krb5_sname_to_principal failed)");
212      goto out;
213    }
214
215  auth.length = cl->req.mr_argl[0];
216  auth.data = cl->req.mr_argv[0];
217
218  status = krb5_rd_req(context, &auth_con, &auth, server, NULL, NULL,
219                        &ticket);
220  if (status)
221    {
222      client_reply(cl, status);
223      com_err(whoami, status, " (krb5 authentication failed)");
224      goto out;
225    }
226
227  status = krb5_copy_principal(context, ticket->enc_part2->client, &client);
228  if (status)
229    {
230      client_reply(cl, status);
231      com_err(whoami, status, " (krb5_copy_principal failed)");
232      goto out;
233    }
234
235  /* Always convert to krb4 style principal name for now. */
236  status = krb5_524_conv_principal(context, client, name, inst, realm);
237  if (status)
238    {
239      client_reply(cl, status);
240      com_err(whoami, status, " (krb5_524_conv_principal failed)");
241      goto out;
242    }
243  status = set_client(cl, mr_kname_unparse(name, inst, realm), name, inst,
244                      realm);
245
246  strncpy(cl->entity, cl->req.mr_argv[1], sizeof(cl->entity) - 1);
247  cl->entity[sizeof(cl->entity) - 1] = 0;
248
249  com_err(whoami, 0, "krb5 auth to %s using %s, uid %d cid %d",
250          cl->clname, cl->entity, cl->users_id, cl->client_id);
251
252  if (status != MR_SUCCESS || cl->users_id != 0)
253    client_reply(cl, status);
254  else
255    client_reply(cl, MR_USER_AUTH);
256
257 out:
258  if (client)
259    krb5_free_principal(context, client);
260  if (server)
261    krb5_free_principal(context, server);
262  if (ticket)
263    krb5_free_ticket(context, ticket);
264  if (auth_con)
265    krb5_auth_con_free(context, auth_con);
266  return;
267}
Note: See TracBrowser for help on using the repository browser.