1 /* authorize.c --- Authorization to services of authenticated principals.
2 * Copyright (C) 2003-2013 Simon Josefsson
3 *
4 * This file is part of Shishi.
5 *
6 * Shishi is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Shishi is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Shishi; if not, see http://www.gnu.org/licenses or write
18 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
19 * Floor, Boston, MA 02110-1301, USA
20 *
21 */
22
23 #include "internal.h"
24
25 #ifdef HAVE_PWD_H
26 # include <pwd.h>
27 #endif
28
29 /**
30 * shishi_authorize_strcmp:
31 * @handle: shishi handle allocated by shishi_init().
32 * @principal: string with desired principal name.
33 * @authzname: authorization name.
34 *
35 * Authorization of @authzname against desired @principal
36 * according to "basic" authentication, i.e., testing for
37 * identical strings.
38 *
39 * Return value: Returns 1 if @authzname is authorized for services
40 * by the encrypted principal, and 0 otherwise.
41 **/
42 int
shishi_authorize_strcmp(Shishi * handle,const char * principal,const char * authzname)43 shishi_authorize_strcmp (Shishi * handle, const char *principal,
44 const char *authzname)
45 {
46 if (strcmp (principal, authzname) == 0)
47 return 1;
48
49 return 0;
50 }
51
52 /* MIT/Heimdal authorization method */
53 /**
54 * shishi_authorize_k5login:
55 * @handle: shishi handle allocated by shishi_init().
56 * @principal: string with desired principal name and realm.
57 * @authzname: authorization name.
58 *
59 * Authorization of @authzname against desired @principal
60 * in accordance with the MIT/Heimdal authorization method.
61 *
62 * Return value: Returns 1 if @authzname is authorized for services
63 * by @principal, and returns 0 otherwise.
64 **/
65 int
shishi_authorize_k5login(Shishi * handle,const char * principal,const char * authzname)66 shishi_authorize_k5login (Shishi * handle, const char *principal,
67 const char *authzname)
68 {
69 #if HAVE_PWD_H && HAVE_GETPWNAM
70 struct passwd *pwd;
71 struct stat sta;
72 FILE *fic;
73 char *ficname;
74 char *line = NULL;
75 size_t linelength = 0;
76 int authorized = 0;
77
78 pwd = getpwnam (authzname);
79 if (pwd == NULL || pwd->pw_dir == NULL)
80 return 0;
81
82 asprintf (&ficname, "%s/%s", pwd->pw_dir, ".k5login");
83
84 if (stat (ficname, &sta) != 0)
85 {
86 /* File .k5login does not exist. */
87 free (ficname);
88 return 0;
89 }
90
91 /* Owner should be acting user, or root. */
92 if ((sta.st_uid != pwd->pw_uid) && (sta.st_uid != 0))
93 {
94 free (ficname);
95 return 0;
96 }
97
98 /* Write access is forbidden for group and world. */
99 if ((sta.st_mode & S_IWGRP) || (sta.st_mode & S_IWOTH))
100 {
101 free (ficname);
102 return 0;
103 }
104
105 fic = fopen (ficname, "r");
106 if (fic == NULL)
107 {
108 free (ficname);
109 return 0;
110 }
111
112 while (!feof (fic))
113 {
114 char *p;
115
116 if (getline (&line, &linelength, fic) == -1)
117 break;
118 p = strchr (line, '\n');
119 if (p)
120 *p = '\0';
121
122 if (strcmp (principal, line) == 0)
123 {
124 authorized = 1;
125 break;
126 }
127 }
128
129 fclose (fic);
130 free (ficname);
131 free (line);
132
133 return authorized;
134 #else
135 return 0;
136 #endif
137 }
138
139 struct Authorization_aliases
140 {
141 const char *name;
142 int type;
143 };
144
145 static const struct Authorization_aliases authorization_aliases[] = {
146 {"basic", SHISHI_AUTHORIZATION_BASIC},
147 {"k5login", SHISHI_AUTHORIZATION_K5LOGIN}
148 };
149
150 /**
151 * shishi_authorization_parse:
152 * @authorization: name of authorization type, "basic" or "k5login".
153 *
154 * Parse authorization type name.
155 *
156 * Return value: Returns authorization type corresponding to a string.
157 **/
158 int
shishi_authorization_parse(const char * authorization)159 shishi_authorization_parse (const char *authorization)
160 {
161 size_t i;
162 char *endptr;
163
164 i = strtol (authorization, &endptr, 0);
165
166 if (endptr != authorization)
167 return i;
168
169 for (i = 0;
170 i < sizeof (authorization_aliases) / sizeof (authorization_aliases[0]);
171 i++)
172 if (strcasecmp (authorization, authorization_aliases[i].name) == 0)
173 return authorization_aliases[i].type;
174
175 return -1;
176 }
177
178 /**
179 * shishi_authorized_p:
180 * @handle: shishi handle allocated by shishi_init().
181 * @tkt: input variable with ticket info.
182 * @authzname: authorization name.
183 *
184 * Simplistic authorization of @authzname against encrypted client
185 * principal name inside ticket. For "basic" authentication type,
186 * the principal name must coincide with @authzname. The "k5login"
187 * authentication type attempts the MIT/Heimdal method of parsing
188 * the file "~/.k5login" for additional equivalence names.
189 *
190 * Return value: Returns 1 if @authzname is authorized for services
191 * by the encrypted principal, and 0 otherwise.
192 **/
193 int
shishi_authorized_p(Shishi * handle,Shishi_tkt * tkt,const char * authzname)194 shishi_authorized_p (Shishi * handle, Shishi_tkt * tkt, const char *authzname)
195 {
196 char *client = NULL, *clientrealm = NULL;
197 size_t i;
198 int rc;
199
200 rc = shishi_encticketpart_client (handle, shishi_tkt_encticketpart (tkt),
201 &client, NULL);
202 if (rc != SHISHI_OK)
203 return 0;
204
205 rc = shishi_encticketpart_clientrealm (handle,
206 shishi_tkt_encticketpart (tkt),
207 &clientrealm, NULL);
208 if (rc != SHISHI_OK)
209 {
210 free (client);
211 return 0;
212 }
213
214 for (i = 0; i < handle->nauthorizationtypes; i++)
215 {
216 switch (handle->authorizationtypes[i])
217 {
218 case SHISHI_AUTHORIZATION_BASIC:
219 if (shishi_authorize_strcmp (handle, client, authzname))
220 {
221 free (client);
222 free (clientrealm);
223 return 1;
224 }
225 break;
226
227 case SHISHI_AUTHORIZATION_K5LOGIN:
228 if (shishi_authorize_k5login (handle, clientrealm, authzname))
229 {
230 free (client);
231 free (clientrealm);
232 return 1;
233 }
234 break;
235
236 default:
237 break; /* Ignore unknown types. Continue searching. */
238 }
239 }
240
241 free (client);
242 free (clientrealm);
243 return 0;
244 }
245