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