source: trunk/athena/lib/locker/afs.c @ 22841

Revision 22841, 20.4 KB checked in by tabbott, 16 years ago (diff)
In locker: * Merged quilt patches into mainline Athena tree
Line 
1/* Copyright 1998 by the Massachusetts Institute of Technology.
2 *
3 * Permission to use, copy, modify, and distribute this
4 * software and its documentation for any purpose and without
5 * fee is hereby granted, provided that the above copyright
6 * notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting
8 * documentation, and that the name of M.I.T. not be used in
9 * advertising or publicity pertaining to distribution of the
10 * software without specific, written prior permission.
11 * M.I.T. makes no representations about the suitability of
12 * this software for any purpose.  It is provided "as is"
13 * without express or implied warranty.
14 */
15
16/* This file is part of liblocker. It implements AFS lockers. */
17
18static const char rcsid[] = "$Id: afs.c,v 1.16 2006-08-08 21:50:09 ghudson Exp $";
19
20#include <sys/types.h>
21#include <sys/socket.h>
22#include <sys/stat.h>
23#include <errno.h>
24#include <netdb.h>
25#include <stdlib.h>
26#include <string.h>
27#include <unistd.h>
28
29#include <afs/stds.h>
30#include <afs/param.h>
31#include <afs/auth.h>
32#include <afs/cellconfig.h>
33#include <afs/ptserver.h>
34#include <afs/ptuser.h>
35#include <afs/venus.h>
36#include <rx/rxkad.h>
37
38/* This is defined in <afs/volume.h>, but it doesn't seem possible to
39 * include that without dragging in most of the rest of the afs
40 * includes as dependencies.
41 */
42#define VNAMESIZE 32
43
44#include <com_err.h>
45#include <krb.h>
46#include <krb5.h>
47
48#include "locker.h"
49#include "locker_private.h"
50
51/* Cheesy test for determining AFS 3.5. */
52#ifndef AFSCONF_CLIENTNAME
53#define AFS35
54#endif
55
56#ifdef AFS35
57#include <afs/dirpath.h>
58#else
59#define AFSDIR_CLIENT_ETC_DIRPATH AFSCONF_CLIENTNAME
60#endif
61
62/*
63 * Why doesn't AFS provide this prototype?
64 */
65extern int pioctl(char *, afs_int32, struct ViceIoctl *, afs_int32);
66
67static int afs_parse(locker_context context, char *name, char *desc,
68                     char *mountpoint, locker_attachent **at);
69static int afs_attach(locker_context context, locker_attachent *at,
70                      char *mountoptions);
71static int afs_detach(locker_context context, locker_attachent *at);
72static int afs_auth(locker_context context, locker_attachent *at,
73                    int mode, int op);
74static int afs_zsubs(locker_context context, locker_attachent *at);
75
76struct locker_ops locker__afs_ops = {
77  "AFS",
78  0,
79  afs_parse,
80  afs_attach,
81  afs_detach,
82  afs_auth,
83  afs_zsubs
84};
85
86static int afs_get_cred(krb5_context context, char *name, char *inst, char *realm,
87                        krb5_creds **creds);
88static int afs_maybe_auth_to_cell(locker_context context, char *name,
89                                  char *cell, int op, int force);
90static int get_user_realm(krb5_context context, char *realm);
91static char *afs_realm_of_cell(krb5_context, struct afsconf_cell *);
92
93extern int krb524_convert_creds_kdc(krb5_context, krb5_creds *, CREDENTIALS *);
94
95static int afs_parse(locker_context context, char *name, char *desc,
96                     char *mountpoint, locker_attachent **atp)
97{
98  locker_attachent *at;
99  char *p, *dup = NULL, *lasts = NULL;
100  int status;
101
102  at = locker__new_attachent(context, &locker__afs_ops);
103  if (!at)
104    return LOCKER_ENOMEM;
105
106  if (!name)
107    {
108      /* This is an explicit description. */
109
110      if (strncmp(desc, "/afs/", 5))
111        {
112          locker__error(context, "%s: Path is not in AFS.\n", desc);
113          status = LOCKER_EPARSE;
114          goto cleanup;
115        }
116
117      at->name = strdup(desc);
118      at->hostdir = strdup(desc);
119      if (mountpoint)
120        at->mountpoint = strdup(mountpoint);
121      else
122        {
123          p = strrchr(desc, '/') + 1;
124          at->mountpoint = malloc(strlen(context->afs_mount_dir) +
125                                  strlen(p) + 2);
126          if (at->mountpoint)
127            sprintf(at->mountpoint, "%s/%s", context->afs_mount_dir, p);
128        }
129      if (!at->name || !at->hostdir || !at->mountpoint)
130        goto mem_error;
131
132      at->mode = LOCKER_AUTH_READWRITE;
133    }
134  else
135    {
136      /* A Hesiod AFS description looks like:
137       * AFS /afs/dev.mit.edu/source/src-current w /mit/source
138       */
139
140      at->name = strdup(name);
141      if (!at->name)
142        goto mem_error;
143
144      dup = strdup(desc);
145      if (!dup)
146        goto mem_error;
147
148      /* Skip "AFS". */
149      if (!strtok_r(dup, " ", &lasts))
150        goto parse_error;
151
152      /* Hostdir */
153      at->hostdir = strtok_r(NULL, " ", &lasts);
154      if (!at->hostdir)
155        goto parse_error;
156      if (strncmp(at->hostdir, "/afs/", 5))
157        {
158          locker__error(context, "%s: Path \"%s\" is not in AFS.\n", name,
159                        at->hostdir);
160          status = LOCKER_EPARSE;
161          goto cleanup;
162        }
163      at->hostdir = strdup(at->hostdir);
164      if (!at->hostdir)
165        goto mem_error;
166
167      /* Auth mode */
168      p = strtok_r(NULL, " ", &lasts);
169      if (!p || *(p + 1))
170        goto parse_error;
171
172      switch (*p)
173        {
174        case 'r':
175          at->mode = LOCKER_AUTH_READONLY;
176          break;
177        case 'w':
178          at->mode = LOCKER_AUTH_READWRITE;
179          break;
180        case 'n':
181          at->mode = LOCKER_AUTH_NONE;
182          break;
183        default:
184          locker__error(context, "%s: Unrecognized auth mode '%c' in "
185                        "description:\n%s\n", name, *p, desc);
186          status = LOCKER_EPARSE;
187          goto cleanup;
188        }
189
190      /* Mountpoint */
191      p = strtok_r(NULL, " ", &lasts);
192      if (!p)
193        goto parse_error;
194      if (mountpoint)
195        at->mountpoint = strdup(mountpoint);
196      else
197        at->mountpoint = strdup(p);
198      if (!at->mountpoint)
199        goto mem_error;
200
201      free(dup);
202      dup = NULL;
203    }
204
205  status = locker__canonicalize_path(context, LOCKER_CANON_CHECK_MOST,
206                                     &(at->mountpoint), &(at->buildfrom));
207  if (status != LOCKER_SUCCESS)
208    goto cleanup;
209
210  *atp = at;
211  return LOCKER_SUCCESS;
212
213mem_error:
214  locker__error(context, "Out of memory parsing locker description.\n");
215  status = LOCKER_ENOMEM;
216  goto cleanup;
217
218parse_error:
219  locker__error(context, "Could not parse locker description "
220                "\"%s\".\n", desc);
221  status = LOCKER_EPARSE;
222
223cleanup:
224  free(dup);
225  locker_free_attachent(context, at);
226  return status;
227}
228
229static int afs_attach(locker_context context, locker_attachent *at,
230                      char *mountoptions)
231{
232  struct stat st1, st2;
233  struct ViceIoctl vio;
234  afs_int32 hosts[8]; /* AFS docs say VIOCWHEREIS won't return more than 8. */
235  uid_t uid = geteuid();
236  int status;
237
238  /* Make sure user can read the destination, and it's a directory. */
239  if (uid != context->user)
240    seteuid(context->user);
241  status = lstat(at->hostdir, &st1);
242  if (uid != context->user)
243    seteuid(uid);
244
245  if (status == -1)
246    {
247     if (errno == ETIMEDOUT)
248        {
249          locker__error(context, "%s: Connection timed out while trying to "
250                        "attach locker.\nThis probably indicates a temporary "
251                        "problem with the file server containing\n"
252                        "this locker. Try again later.\n", at->name);
253        }
254      else
255        {
256          locker__error(context, "%s: Could not attach locker:\n%s for %s\n",
257                        at->name, strerror(errno), at->hostdir);
258        }
259      return LOCKER_EATTACH;
260    }
261  if (!S_ISDIR(st1.st_mode) && !S_ISLNK(st1.st_mode))
262    {
263      locker__error(context, "%s: Could not attach locker:\n"
264                    "%s is not a directory.\n", at->name, at->hostdir);
265      return LOCKER_EATTACH;
266    }
267
268  /* Make sure nothing is already mounted on our mountpoint. */
269  status = stat(at->mountpoint, &st2);
270  if (!status)
271    {
272      /* Assume the automounter took care of it */
273    }
274  else
275    {
276    status = symlink(at->hostdir, at->mountpoint);
277    if (status < 0)
278      {
279        locker__error(context, "%s: Could not attach locker:\n%s while "
280                    "symlinking %s to %s\n", at->name, strerror(errno),
281                    at->hostdir, at->mountpoint);
282        return LOCKER_EATTACH;
283      }
284    }
285
286  /* Find host that the locker is on, and update the attachent. */
287  memset(hosts, 0, sizeof(hosts));
288  vio.in_size = 0;
289  vio.out = (caddr_t)hosts;
290  vio.out_size = sizeof(hosts);
291  if (pioctl(at->hostdir, VIOCWHEREIS, &vio, 1) == 0)
292    {
293      /* Only record the hostaddr if the locker is on a single host.
294       * (We assume that if it's on multiple hosts, it can't fail,
295       * so we don't need to know what those hosts are.)
296       */
297      if (!hosts[1])
298        at->hostaddr.s_addr = hosts[0];
299    }
300
301  return LOCKER_SUCCESS;
302}
303
304static int afs_detach(locker_context context, locker_attachent *at)
305{
306  int status;
307
308  /* Let the automounter manage the symlink */
309  /* status = unlink(at->mountpoint);
310  if (status < 0)
311    {
312      if (errno == ENOENT)
313        {
314          locker__error(context, "%s: Locker is not attached.\n", at->name);
315          return LOCKER_ENOTATTACHED;
316        }
317      else
318        {
319          locker__error(context, "%s: Could not detach locker:\n%s while "
320                        "trying to unlink %s.\n", at->name, strerror(errno),
321                        at->mountpoint);
322          return LOCKER_EDETACH;
323        }
324    }
325  */
326  return LOCKER_SUCCESS;
327}
328
329static int afs_auth(locker_context context, locker_attachent *at,
330                    int mode, int op)
331{
332  char *cell, *p;
333  int status;
334
335  if (op != LOCKER_AUTH_AUTHENTICATE)
336    return LOCKER_SUCCESS;
337
338  /* We know (from afs_parse) that at->hostdir starts with "/afs/". */
339  cell = at->hostdir + 5;
340  /* Skip initial "." in the cell name (if this is a path to a rw volume). */
341  if (*cell == '.')
342    cell++;
343
344  p = strchr(cell, '/');
345  if (p)
346    *p = '\0';
347  status = afs_maybe_auth_to_cell(context, at->name, cell, op, 0);
348  if (p)
349    *p = '/';
350  return status;
351}
352
353int locker_auth_to_cell(locker_context context, char *name, char *cell, int op)
354{
355  return afs_maybe_auth_to_cell(context, name, cell, op, 1);
356}
357
358static int afs_maybe_auth_to_cell(locker_context context, char *name,
359                                  char *cell, int op, int force)
360{
361  char *crealm, urealm[REALM_SZ], *user = NULL;
362  int status;
363  struct afsconf_dir *configdir;
364  struct afsconf_cell cellconfig;
365  struct ktc_principal server, client, xclient;
366  struct ktc_token token, xtoken;
367  afs_int32 vice_id;
368  uid_t uid = geteuid(), ruid = getuid();
369  krb5_context v5context;
370  krb5_creds *v5cred = NULL;
371
372  if (op != LOCKER_AUTH_AUTHENTICATE)
373    return LOCKER_SUCCESS;
374
375  /* Find the cell's db servers. */
376  configdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH);
377  if (!configdir)
378    {
379      locker__error(context, "%s: Could not authenticate to AFS: "
380                    "error opening CellServDB file.\n", name);
381      return LOCKER_EAUTH;
382    }
383  status = afsconf_GetCellInfo(configdir, cell, NULL, &cellconfig);
384  afsconf_Close(configdir);
385  if (status)
386    {
387      initialize_acfg_error_table();
388      locker__error(context, "%s: Could not authenticate to AFS:\n%s while "
389                    "reading CellServDB file.\n", name, error_message(status));
390      return LOCKER_EAUTH;
391    }
392
393  /* Canonicalize the cell name. */
394  cell = cellconfig.name;
395
396  /* Get tickets for the realm containing the cell's servers. (Set uid
397   * to the user before touching the ticket file.) Try
398   * afs.cellname@realm first, and afs@realm if that doesn't exist.
399   */
400  status = krb5_init_context(&v5context);
401  if (status)
402    {
403      locker__error(context, "%s: Could not establish krb5 context: %s\n",
404                    name, error_message(status));
405      return LOCKER_EAUTH;
406    }
407  crealm = afs_realm_of_cell(v5context, &cellconfig);
408  if (uid != ruid)
409    seteuid(ruid);
410  status = afs_get_cred(v5context, "afs", cell, crealm, &v5cred);
411  if (status)
412    status = afs_get_cred(v5context, "afs", "", crealm, &v5cred);
413  if (uid != ruid)
414    seteuid(uid);
415  if (status)
416    {
417      if (status == KRB5_FCC_NOFILE)
418        {
419          locker__error(context, "%s: Could not authenticate to AFS: %s.\n",
420                        name, error_message(status));
421        }
422      else
423        {
424          locker__error(context, "%s: Could not authenticate to AFS cell "
425                        "%s:\n%s while getting tickets for %s.\n",
426                        name, cell, error_message(status), crealm);
427        }
428      krb5_free_context(v5context);
429      return LOCKER_EAUTH;
430    }
431  status = get_user_realm(v5context, urealm);
432  if (status)
433    {
434      locker__error(context, "Couldn't obtain user's realm.\n");
435      return LOCKER_EAUTH;
436    }
437
438  /*
439   * Create a token from the ticket.
440   * (This code is shamelessly stolen from aklog.)
441   */
442
443  if (! context->use_krb4)
444    {
445      char *p;
446      char *pname, *pinst = NULL;
447      int pnamelen, pinstlen = 0;
448
449      /* Using Kerberos V5 ticket natively via rxkad 2b */
450
451      pname    = krb5_princ_component(v5context, v5cred->client, 0)->data;
452      pnamelen = krb5_princ_component(v5context, v5cred->client, 0)->length;
453
454      if (krb5_princ_size(v5context, v5cred->client) > 1)
455        {
456          pinst    = krb5_princ_component(v5context, v5cred->client, 1)->data;
457          pinstlen = krb5_princ_component(v5context, v5cred->client, 1)->length;
458        }
459
460      user = malloc(pnamelen + pinstlen + strlen(urealm) + 3);
461      if (!user)
462        {
463          locker__error(context, "Out of memory authenticating to cell.\n");
464          return LOCKER_ENOMEM;
465        }
466
467      strncpy(user, pname, pnamelen);
468      user[pnamelen] = '\0';
469
470      if (pinst)
471        {
472          strcat(user, ".");
473          p = user + strlen(user);
474          strncpy(p, pinst, pinstlen);
475          p[pinstlen] = '\0';
476        }
477
478      if (strcasecmp(crealm, urealm))
479        sprintf(user + strlen(user), "@%s", urealm);
480
481      memset(&token, 0, sizeof(token));
482      token.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
483      token.startTime = v5cred->times.starttime;;
484      token.endTime = v5cred->times.endtime;
485      memcpy(&token.sessionKey, v5cred->keyblock.contents,
486             v5cred->keyblock.length);
487      token.ticketLen = v5cred->ticket.length;
488      memcpy(token.ticket, v5cred->ticket.data, token.ticketLen);
489    }
490  else
491    {
492      CREDENTIALS cred;
493
494      /* Using Kerberos 524 translator service */
495
496      status = krb5_524_convert_creds(v5context, v5cred, &cred);
497
498      if (status)
499        {
500          locker__error(context, "%s: Could not convert tickets "
501                        "to Kerberos V4 format: %s.\n",
502                        name, error_message(status));
503          krb5_free_context(v5context);
504          return LOCKER_EAUTH;
505        }
506
507      user = malloc(strlen(cred.pname) + strlen(cred.pinst) + strlen(urealm) + 3);
508      if (!user)
509        {
510          locker__error(context, "Out of memory authenticating to cell.\n");
511          return LOCKER_ENOMEM;
512        }
513
514      strcpy(user, cred.pname);
515      if (*cred.pinst)
516        sprintf(user + strlen(user), ".%s", cred.pinst);
517      if (strcasecmp(crealm, urealm))
518        sprintf(user + strlen(user), "@%s", urealm);
519
520      token.kvno = cred.kvno;
521      token.startTime = cred.issue_date;
522      token.endTime = v5cred->times.endtime;
523      memcpy(&token.sessionKey, cred.session, sizeof(token.sessionKey));
524      token.ticketLen = cred.ticket_st.length;
525      memcpy(token.ticket, cred.ticket_st.dat, token.ticketLen);
526    }
527
528  krb5_free_creds(v5context, v5cred);
529  krb5_free_context(v5context);
530
531  /* Look up principal's PTS id. */
532  status = pr_Initialize(0, (char *)AFSDIR_CLIENT_ETC_DIRPATH, cell);
533  if (status)
534    {
535      locker__error(context, "%s: Could not initialize AFS protection "
536                    "library while authenticating to cell \"%s\":\n%s.\n",
537                    name, cell, error_message(status));
538      free(user);
539      return LOCKER_EAUTH;
540    }
541  status = pr_SNameToId(user, &vice_id);
542  if (status)
543    {
544      locker__error(context, "%s: Could not find AFS PTS id for user \"%s\""
545                    "in cell \"%s\":\n%s.\n", name, user, cell,
546                    error_message(status));
547      free(user);
548      return LOCKER_EAUTH;
549    }
550
551  /* Select appropriate dead chicken to wave. */
552  if (vice_id == ANONYMOUSID)
553    strncpy(client.name, user, MAXKTCNAMELEN - 1);
554  else
555    sprintf(client.name, "AFS ID %ld", (long) vice_id);
556  strcpy(client.instance, "");
557  strncpy(client.cell, crealm, MAXKTCREALMLEN - 1);
558  client.cell[MAXKTCREALMLEN - 1] = '\0';
559
560  strcpy(server.name, "afs");
561  strcpy(server.instance, "");
562  strncpy(server.cell, cell, MAXKTCREALMLEN - 1);
563  server.cell[MAXKTCREALMLEN - 1] = '\0';
564
565  if (!force)
566    {
567      /* Check for an existing token. */
568      status = ktc_GetToken(&server, &xtoken, sizeof(token), &xclient);
569      if (!status)
570        {
571          /* Don't get tokens as another user. */
572          if (strcmp(xclient.name, client.name))
573            {
574              free(user);
575              return LOCKER_SUCCESS;
576            }
577
578          /* Don't get tokens that won't last longer than existing tokens. */
579          if (token.endTime <= xtoken.endTime)
580            {
581              free(user);
582              return LOCKER_SUCCESS;
583            }
584        }
585    }
586
587  /* Store the token. */
588  status = ktc_SetToken(&server, &token, &client, 0);
589  if (status)
590    {
591      locker__error(context, "%s: Could not obtain %s tokens for cell "
592                    "%s:\n%s.\n", name, user, cell, error_message(status));
593      free(user);
594      return LOCKER_EAUTH;
595    }
596
597  free(user);
598  return LOCKER_SUCCESS;
599}
600
601static int afs_get_cred(krb5_context context, char *name, char *inst, char *realm,
602                        krb5_creds **creds)
603{
604  krb5_creds increds;
605  krb5_principal client_principal = NULL;
606  krb5_ccache krb425_ccache = NULL;
607  krb5_error_code retval = 0;
608
609  memset(&increds, 0, sizeof(increds));
610  /* ANL - instance may be ptr to a null string. Pass null then */
611  retval = krb5_build_principal(context, &increds.server, strlen(realm),
612                                realm, name,
613                                (inst && strlen(inst)) ? inst : NULL,
614                                NULL);
615  if (retval)
616    goto fail;
617
618  retval = krb5_cc_default(context, &krb425_ccache);
619  if (retval)
620    goto fail;
621
622  retval = krb5_cc_get_principal(context, krb425_ccache, &client_principal);
623  if (retval)
624    goto fail;
625
626  increds.client = client_principal;
627  increds.times.endtime = 0;
628  /* Ask for DES since that is what V4 understands */
629  increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
630
631  retval = krb5_get_credentials(context, 0, krb425_ccache, &increds, creds);
632
633fail:
634  krb5_free_cred_contents(context, &increds);
635  if (krb425_ccache)
636    krb5_cc_close(context, krb425_ccache);
637  return(retval);
638}
639
640static int afs_zsubs(locker_context context, locker_attachent *at)
641{
642  struct ViceIoctl vio;
643  char *path, *last_component, *p, *subs[3];
644  char cell[MAXCELLCHARS + 1], vol[VNAMESIZE + 1];
645  char cellvol[MAXCELLCHARS + VNAMESIZE + 2];
646  afs_int32 hosts[8];
647  int status = 0, pstatus;
648  struct hostent *h;
649
650  subs[0] = cell;
651  subs[1] = cellvol;
652
653  path = strdup(at->hostdir);
654  if (!path)
655    {
656      locker__error(context, "Out of memory getting zephyr subscriptions.\n");
657      return LOCKER_ENOMEM;
658    }
659
660  /* Walk down the path. At each level, add subscriptions for the cell,
661   * host, and volume where that path component lives.
662   */
663  p = path;
664  do
665    {
666      /* Move trailing NUL over one pathname component. */
667      *p = '/';
668      p = strchr(p + 1, '/');
669      if (p)
670        *p = '\0';
671
672      /* Get cell */
673      vio.in_size = 0;
674      vio.out = cell;
675      vio.out_size = sizeof(cell);
676      if (pioctl(path, VIOC_FILE_CELL_NAME, &vio, 1) != 0)
677        continue;
678
679      /* Get mountpoint name and generate cell:mountpoint. */
680      last_component = strrchr(path, '/');
681      if (last_component)
682        {
683          *last_component++ = '\0';
684          vio.in = last_component;
685        }
686      else
687        vio.in = "/";
688      vio.in_size = strlen(vio.in) + 1;
689      vio.out = vol;
690      vio.out_size = sizeof(vol);
691      pstatus = pioctl(path, VIOC_AFS_STAT_MT_PT, &vio, 1);
692      if (last_component)
693        *(last_component - 1) = '/';
694
695      if (pstatus != 0)
696        continue;
697
698      /* Get cell:volumname into cellvol, ignoring initial '#' or '%'. */
699      if (strchr(vol, ':'))
700        strcpy(cellvol, vol + 1);
701      else
702        sprintf(cellvol, "%s:%s", cell, vol + 1);
703
704      /* If there's only one site for this volume, add the hostname
705       * of the server to the subs list.
706       */
707      memset(hosts, 0, 2 * sizeof(*hosts));
708      vio.out = (caddr_t)hosts;
709      vio.out_size = sizeof(hosts);
710      if (pioctl(path, VIOCWHEREIS, &vio, 1) != 0)
711        continue;
712      if (!hosts[1])
713        {
714          h = gethostbyaddr((char *)&hosts[0], 4, AF_INET);
715          if (!h)
716            continue;
717          subs[2] = h->h_name;
718          status = locker__add_zsubs(context, subs, 3);
719        }
720      else
721        status = locker__add_zsubs(context, subs, 2);
722    }
723  while (status == LOCKER_SUCCESS && strlen(path) != strlen(at->hostdir));
724
725  free(path);
726  return status;
727}
728
729/* librxkad depends on this symbol in Transarc's des library, which we
730 * can't link with because of conflicts with our krb4 library. It never
731 * gets called though.
732 */
733void des_pcbc_init(void)
734{
735  abort();
736}
737
738static char *afs_realm_of_cell(context, cellconfig)
739     krb5_context context;
740     struct afsconf_cell *cellconfig;
741{
742  static char krbrlm[REALM_SZ+1];
743  char **hrealms = 0;
744
745  if (!cellconfig)
746    return 0;
747  if (krb5_get_host_realm(context, cellconfig->hostName[0], &hrealms))
748    return 0;
749  if (!hrealms[0])
750    return 0;
751  strcpy(krbrlm, hrealms[0]);
752
753  if (hrealms)
754    free(hrealms);
755
756  return krbrlm;
757}
758
759static int get_user_realm(krb5_context context, char *realm)
760{
761  krb5_principal client_principal = NULL;
762  krb5_ccache krb425_ccache = NULL;
763  krb5_error_code retval = 0;
764  int i;
765
766  retval = krb5_cc_default(context, &krb425_ccache);
767  if (retval)
768    goto fail;
769
770  retval = krb5_cc_get_principal(context, krb425_ccache, &client_principal);
771  if (retval)
772    goto fail;
773
774  i = krb5_princ_realm(context, client_principal)->length;
775  if (i > REALM_SZ - 1)
776    i = REALM_SZ - 1;
777  memcpy(realm, krb5_princ_realm(context, client_principal)->data, i);
778  realm[i] = '\0';
779
780fail:
781  if (krb425_ccache)
782    krb5_cc_close(context, krb425_ccache);
783  if (client_principal)
784    krb5_free_principal(context, client_principal);
785
786  return retval;
787}
Note: See TracBrowser for help on using the repository browser.