1 /*
2  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 #pragma ident	"%Z%%M%	%I%	%E% SMI"
7 
8 /*
9  * lib/krb5/krb/srv_rcache.c
10  *
11  * Copyright 1991 by the Massachusetts Institute of Technology.
12  * All Rights Reserved.
13  *
14  * Export of this software from the United States of America may
15  *   require a specific license from the United States Government.
16  *   It is the responsibility of any person or organization contemplating
17  *   export to obtain such a license before exporting.
18  *
19  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
20  * distribute this software and its documentation for any purpose and
21  * without fee is hereby granted, provided that the above copyright
22  * notice appear in all copies and that both that copyright notice and
23  * this permission notice appear in supporting documentation, and that
24  * the name of M.I.T. not be used in advertising or publicity pertaining
25  * to distribution of the software without specific, written prior
26  * permission.  Furthermore if you modify this software you must label
27  * your software as modified software and not distribute it in such a
28  * fashion that it might be confused with the original M.I.T. software.
29  * M.I.T. makes no representations about the suitability of
30  * this software for any purpose.  It is provided "as is" without express
31  * or implied warranty.
32  *
33  *
34  * Allocate & prepare a default replay cache for a server.
35  */
36 
37 #include <k5-int.h>
38 #include <ctype.h>
39 #include <stdio.h>
40 
41 #define isvalidrcname(x) ((!ispunct(x))&&isgraph(x))
42 krb5_error_code KRB5_CALLCONV
43 krb5_get_server_rcache(krb5_context context, const krb5_data *piece,
44 		       krb5_rcache *rcptr)
45 {
46     krb5_rcache rcache = 0;
47     char *cachename = 0, *def_env = 0, *cachetype;
48     char tmp[4];
49     krb5_error_code retval;
50     int p, i;
51     unsigned int len;
52 
53 #ifdef HAVE_GETEUID
54     unsigned long tens;
55     unsigned long uid = geteuid();
56 #endif
57 
58     if (piece == NULL)
59 	return ENOMEM;
60 
61 /*
62  * Check to see if something other than the default replay cache
63  * name will be used.  If so then skip over the construction of
64  * said name.
65  */
66     if ((def_env = krb5_rc_default_name(context)) != 0) {
67 	cachename = strdup(def_env);
68 	if (!cachename) {
69 		return (ENOMEM);
70 	}
71 	goto skip_create;
72     }
73 
74     cachetype = krb5_rc_default_type(context);
75 
76     len = piece->length + 3 + 1;
77     for (i = 0; i < piece->length; i++) {
78 	if (piece->data[i] == '-')
79 	    len++;
80 	else if (!isvalidrcname((int) piece->data[i]))
81 	    len += 3;
82     }
83 
84 #ifdef HAVE_GETEUID
85     len += 2;	/* _<uid> */
86     for (tens = 1; (uid / tens) > 9 ; tens *= 10)
87 	len++;
88 #endif
89 
90     cachename = malloc(strlen(cachetype) + 5 + len);
91     if (!cachename) {
92 	retval = ENOMEM;
93 	goto cleanup;
94     }
95     strcpy(cachename, cachetype);
96 
97     p = strlen(cachename);
98     cachename[p++] = ':';
99     for (i = 0; i < piece->length; i++) {
100 	if (piece->data[i] == '-') {
101 	    cachename[p++] = '-';
102 	    cachename[p++] = '-';
103 	    continue;
104 	}
105 	if (!isvalidrcname((int) piece->data[i])) {
106 	    sprintf(tmp, "%03o", piece->data[i]);
107 	    cachename[p++] = '-';
108 	    cachename[p++] = tmp[0];
109 	    cachename[p++] = tmp[1];
110 	    cachename[p++] = tmp[2];
111 	    continue;
112 	}
113 	cachename[p++] = piece->data[i];
114     }
115 
116 #ifdef HAVE_GETEUID
117     cachename[p++] = '_';
118     while (tens) {
119 	cachename[p++] = '0' + ((uid / tens) % 10);
120 	tens /= 10;
121     }
122 #endif
123 
124     cachename[p++] = '\0';
125 
126 skip_create:
127     retval = krb5_rc_resolve_full(context, &rcache, cachename);
128     if (retval)
129 	goto cleanup;
130 
131     /*
132      * First try to recover the replay cache; if that doesn't work,
133      * initialize it.
134      */
135     retval = krb5_rc_recover_or_initialize(context, rcache, context->clockskew);
136     if (retval) {
137 	krb5_rc_close(context, rcache);
138 	rcache = 0;
139 	goto cleanup;
140     }
141 
142     *rcptr = rcache;
143     rcache = 0;
144     retval = 0;
145 
146 cleanup:
147     if (rcache)
148 	krb5_xfree(rcache);
149     if (cachename)
150 	krb5_xfree(cachename);
151     return retval;
152 }
153