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

Revision 24319, 6.7 KB checked in by broder, 14 years ago (diff)
New Moira snapshot from SVN.
Line 
1/* $Id: mr_sauth.c 3956 2010-01-05 20:56:56Z zacheiss $
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("$HeadURL: svn+ssh://svn.mit.edu/moira/trunk/moira/server/mr_sauth.c $ $Id: mr_sauth.c 3956 2010-01-05 20:56:56Z zacheiss $");
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
31#ifdef HAVE_KRB4
32typedef struct _replay_cache {
33  KTEXT_ST auth;
34  time_t expires;
35  struct _replay_cache *next;
36} replay_cache;
37
38replay_cache *rcache = NULL;
39#endif
40
41/*
42 * Handle a MOIRA_AUTH RPC request.
43 *
44 * argv[0] is a kerberos authenticator.  Decompose it, and if
45 * successful, store the name the user authenticated to in
46 * cl->cl_name.
47 */
48
49void do_auth(client *cl)
50{
51#ifdef HAVE_KRB4
52  KTEXT_ST auth;
53  AUTH_DAT ad;
54  int status;
55  replay_cache *rc, *rcnew;
56  time_t now;
57
58  auth.length = cl->req.mr_argl[0];
59  memcpy(auth.dat, cl->req.mr_argv[0], auth.length);
60  auth.mbz = 0;
61
62  if ((status = krb_rd_req(&auth, MOIRA_SNAME, host,
63                           cl->haddr.sin_addr.s_addr, &ad, "")))
64    {
65      status += ERROR_TABLE_BASE_krb;
66      client_reply(cl, status);
67      com_err(whoami, status, " (authentication failed)");
68      return;
69    }
70
71  if (!rcache)
72    {
73      rcache = xmalloc(sizeof(replay_cache));
74      memset(rcache, 0, sizeof(replay_cache));
75    }
76
77  /* scan replay cache */
78  for (rc = rcache->next; rc; rc = rc->next)
79    {
80      if (auth.length == rc->auth.length &&
81          !memcmp(&(auth.dat), &(rc->auth.dat), auth.length))
82        {
83          com_err(whoami, 0,
84                  "Authenticator replay from %s using authenticator for %s",
85                  inet_ntoa(cl->haddr.sin_addr),
86                  mr_kname_unparse(ad.pname, ad.pinst, ad.prealm));
87          com_err(whoami, KE_RD_AP_REPEAT, " (authentication failed)");
88          client_reply(cl, KE_RD_AP_REPEAT);
89          return;
90        }
91    }
92
93  /* add new entry */
94  time(&now);
95  rcnew = xmalloc(sizeof(replay_cache));
96  memcpy(&(rcnew->auth), &auth, sizeof(KTEXT_ST));
97  rcnew->expires = now + 2 * CLOCK_SKEW;
98  rcnew->next = rcache->next;
99  rcache->next = rcnew;
100
101  /* clean cache */
102  for (rc = rcnew; rc->next; )
103    {
104      if (rc->next->expires < now)
105        {
106          rcnew = rc->next;
107          rc->next = rc->next->next;
108          free(rcnew);
109        }
110      else
111        rc = rc->next;
112    }
113
114  status = set_client(cl, mr_kname_unparse(ad.pname, ad.pinst, ad.prealm),
115                      ad.pname, ad.pinst, ad.prealm);
116
117  strncpy(cl->entity, cl->req.mr_argv[1], sizeof(cl->entity) - 1);
118  cl->entity[sizeof(cl->entity) - 1] = 0;
119
120  memset(&ad, 0, sizeof(ad));   /* Clean up session key, etc. */
121
122  com_err(whoami, 0, "Auth to %s using %s, uid %d cid %d",
123          cl->clname, cl->entity, cl->users_id, cl->client_id);
124
125  if (status != MR_SUCCESS || cl->users_id != 0)
126    client_reply(cl, status);
127  else
128    client_reply(cl, MR_USER_AUTH);
129#else
130  client_reply(cl, MR_NO_KRB4);
131#endif
132}
133
134void do_proxy(client *cl)
135{
136  char name[ANAME_SZ] = "\0", inst[INST_SZ] = "\0", realm[REALM_SZ] = "\0";
137  char kname[MAX_K_NAME_SZ];
138
139  if (cl->proxy_id)
140    {
141      com_err(whoami, MR_PERM, "Cannot re-proxy");
142      client_reply(cl, MR_PERM);
143      return;
144    }
145
146  if (mr_kname_parse(name, inst, realm, cl->req.mr_argv[0]) != 0)
147    {
148      com_err(whoami, KE_KNAME_FMT, "while parsing proxy name %s",
149              cl->req.mr_argv);
150      client_reply(cl, KE_KNAME_FMT);
151      return;
152    }
153
154  if (!*realm)
155    {
156      strcpy(realm, krb_realm);
157      sprintf(kname, "%s@%s", cl->req.mr_argv[0], realm);
158    }
159  else
160    strcpy(kname, cl->req.mr_argv[0]);
161   
162  if (find_member("LIST", proxy_acl, cl))
163    {
164      cl->proxy_id = cl->client_id;
165      set_client(cl, kname, name, inst, realm);
166      com_err(whoami, 0, "Proxy authentication as %s (uid %d cid %d) via %s",
167              kname, cl->users_id, cl->client_id, cl->req.mr_argv[1]);
168      client_reply(cl, MR_SUCCESS);
169    }
170  else
171    {
172      com_err(whoami, MR_PERM, "Proxy authentication denied");
173      client_reply(cl, MR_PERM);
174    }
175}
176
177static int set_client(client *cl, char *kname,
178                      char *name, char *inst, char *realm)
179{
180  int ok;
181
182  strncpy(cl->clname, kname, sizeof(cl->clname));
183  cl->clname[sizeof(cl->clname) - 1] = '\0';
184
185  if ((!inst || inst[0] == 0) && !strcmp(realm, krb_realm))
186    ok = 1;
187  else
188    ok = 0;
189  /* this is in a separate function because it accesses the database */
190  return set_krb_mapping(cl->clname, name, ok, &cl->client_id, &cl->users_id);
191}
192
193void do_krb5_auth(client *cl)
194{
195  krb5_data auth;
196  krb5_auth_context auth_con = NULL;
197  krb5_principal server = NULL, client = NULL;
198  krb5_ticket *ticket;
199  char name[ANAME_SZ], inst[INST_SZ], realm[REALM_SZ];
200  int status;
201
202  ticket = NULL;
203
204  status = krb5_auth_con_init(context, &auth_con);
205  if (status)
206    {
207      client_reply(cl, status);
208      com_err(whoami, status, "(krb5 auth context init failed)");
209      goto out;
210    }
211
212  status = krb5_sname_to_principal(context, host, MOIRA_SNAME,
213                                    KRB5_NT_SRV_HST, &server);
214  if (status)
215    {
216      client_reply(cl, status);
217      com_err(whoami, status, "(krb5_sname_to_principal failed)");
218      goto out;
219    }
220
221  auth.length = cl->req.mr_argl[0];
222  auth.data = cl->req.mr_argv[0];
223
224  status = krb5_rd_req(context, &auth_con, &auth, server, NULL, NULL,
225                        &ticket);
226  if (status)
227    {
228      client_reply(cl, status);
229      com_err(whoami, status, " (krb5 authentication failed)");
230      goto out;
231    }
232
233  status = krb5_copy_principal(context, ticket->enc_part2->client, &client);
234  if (status)
235    {
236      client_reply(cl, status);
237      com_err(whoami, status, " (krb5_copy_principal failed)");
238      goto out;
239    }
240
241  /* Always convert to krb4 style principal name for now. */
242  status = krb5_524_conv_principal(context, client, name, inst, realm);
243  if (status)
244    {
245      client_reply(cl, status);
246      com_err(whoami, status, " (krb5_524_conv_principal failed)");
247      goto out;
248    }
249  status = set_client(cl, mr_kname_unparse(name, inst, realm), name, inst,
250                      realm);
251
252  strncpy(cl->entity, cl->req.mr_argv[1], sizeof(cl->entity) - 1);
253  cl->entity[sizeof(cl->entity) - 1] = 0;
254
255  com_err(whoami, 0, "krb5 auth to %s using %s, uid %d cid %d",
256          cl->clname, cl->entity, cl->users_id, cl->client_id);
257
258  if (status != MR_SUCCESS || cl->users_id != 0)
259    client_reply(cl, status);
260  else
261    client_reply(cl, MR_USER_AUTH);
262
263 out:
264  if (client)
265    krb5_free_principal(context, client);
266  if (server)
267    krb5_free_principal(context, server);
268  if (ticket)
269    krb5_free_ticket(context, ticket);
270  if (auth_con)
271    krb5_auth_con_free(context, auth_con);
272  return;
273}
Note: See TracBrowser for help on using the repository browser.