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