1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 #include <alloca.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/stat.h>
30 #include <pwd.h>
31 #include <nss_dbdefs.h>
32 #include <deflt.h>
33 #include <auth_attr.h>
34 #include <prof_attr.h>
35 #include <user_attr.h>
36
37 #define COPYTOSTACK(dst, csrc) { \
38 size_t len = strlen(csrc) + 1; \
39 dst = alloca(len); \
40 (void) memcpy(dst, csrc, len); \
41 }
42
43 static kva_t *get_default_attrs(const char *);
44 static void free_default_attrs(kva_t *);
45
46 /*
47 * Enumeration functions for auths and profiles; the enumeration functions
48 * take a callback with four arguments:
49 * const char * profile name (or NULL unless wantattr is false)
50 * kva_t * attributes (or NULL unless wantattr is true)
51 * void * context
52 * void * pointer to the result
53 * When the call back returns non-zero, the enumeration ends.
54 * The function might be NULL but only for profiles as we are always collecting
55 * all the profiles.
56 * Both the auths and the profiles arguments may be NULL.
57 *
58 * These should be the only implementation of the algorithm of "finding me
59 * all the profiles/athorizations/keywords/etc.
60 */
61
62 #define CONSUSER_PROFILE_KW "consprofile"
63 #define DEF_LOCK_AFTER_RETRIES "LOCK_AFTER_RETRIES="
64
65 static struct dfltplcy {
66 char *attr;
67 const char *defkw;
68 } dfltply[] = {
69 /* CONSUSER MUST BE FIRST! */
70 { CONSUSER_PROFILE_KW, DEF_CONSUSER},
71 { PROFATTR_AUTHS_KW, DEF_AUTH},
72 { PROFATTR_PROFS_KW, DEF_PROF},
73 { USERATTR_LIMPRIV_KW, DEF_LIMITPRIV},
74 { USERATTR_DFLTPRIV_KW, DEF_DFLTPRIV},
75 { USERATTR_LOCK_AFTER_RETRIES_KW, DEF_LOCK_AFTER_RETRIES}
76 };
77
78 #define NDFLTPLY (sizeof (dfltply)/sizeof (struct dfltplcy))
79 #define GETCONSPROF(a) (kva_match((a), CONSUSER_PROFILE_KW))
80 #define GETPROF(a) (kva_match((a), PROFATTR_PROFS_KW))
81
82 /*
83 * Enumerate profiles from listed profiles.
84 */
85 static int _auth_match_noun(const char *, const char *, size_t, const char *);
86
87 int
_enum_common_p(const char * cprofiles,int (* cb)(const char *,kva_t *,void *,void *),void * ctxt,void * pres,boolean_t wantattr,int * pcnt,char * profs[MAXPROFS])88 _enum_common_p(const char *cprofiles,
89 int (*cb)(const char *, kva_t *, void *, void *),
90 void *ctxt, void *pres, boolean_t wantattr,
91 int *pcnt, char *profs[MAXPROFS])
92 {
93 char *prof, *last;
94 char *profiles;
95 profattr_t *pa;
96 int i;
97 int res = 0;
98
99 if (cprofiles == NULL)
100 return (0);
101
102 if (*pcnt > 0 && strcmp(profs[*pcnt - 1], PROFILE_STOP) == NULL)
103 return (0);
104
105 COPYTOSTACK(profiles, cprofiles)
106
107 while (prof = strtok_r(profiles, KV_SEPSTR, &last)) {
108
109 profiles = NULL; /* For next iterations of strtok_r */
110
111 for (i = 0; i < *pcnt; i++)
112 if (strcmp(profs[i], prof) == 0)
113 goto cont;
114
115 if (*pcnt >= MAXPROFS) /* oops: too many profs */
116 return (-1);
117
118 /* Add it */
119 profs[(*pcnt)++] = strdup(prof);
120
121 if (strcmp(profs[*pcnt - 1], PROFILE_STOP) == 0)
122 break;
123
124 /* find the profiles for this profile */
125 pa = getprofnam(prof);
126
127 if (cb != NULL && (!wantattr || pa != NULL && pa->attr != NULL))
128 res = cb(prof, pa ? pa->attr : NULL, ctxt, pres);
129
130 if (pa != NULL) {
131 if (res == 0 && pa->attr != NULL) {
132 res = _enum_common_p(GETPROF(pa->attr), cb,
133 ctxt, pres, wantattr, pcnt, profs);
134 }
135 free_profattr(pa);
136 }
137 if (res != 0)
138 return (res);
139 cont:
140 continue;
141 }
142 return (res);
143 }
144
145 /*
146 * Enumerate all attributes associated with a username and the profiles
147 * associated with the user.
148 */
149 static int
_enum_common(const char * username,int (* cb)(const char *,kva_t *,void *,void *),void * ctxt,void * pres,boolean_t wantattr)150 _enum_common(const char *username,
151 int (*cb)(const char *, kva_t *, void *, void *),
152 void *ctxt, void *pres, boolean_t wantattr)
153 {
154 userattr_t *ua;
155 int res = 0;
156 int cnt = 0;
157 char *profs[MAXPROFS];
158 kva_t *kattrs;
159
160 if (cb == NULL)
161 return (-1);
162
163 ua = getusernam(username);
164
165 if (ua != NULL) {
166 if (ua->attr != NULL) {
167 if (wantattr)
168 res = cb(NULL, ua->attr, ctxt, pres);
169 if (res == 0) {
170 res = _enum_common_p(GETPROF(ua->attr),
171 cb, ctxt, pres, wantattr, &cnt, profs);
172 }
173 }
174 free_userattr(ua);
175 if (res != 0) {
176 free_proflist(profs, cnt);
177 return (res);
178 }
179 }
180
181 if ((cnt == 0 || strcmp(profs[cnt-1], PROFILE_STOP) != 0) &&
182 (kattrs = get_default_attrs(username)) != NULL) {
183
184 res = _enum_common_p(GETCONSPROF(kattrs), cb, ctxt, pres,
185 wantattr, &cnt, profs);
186
187 if (res == 0) {
188 res = _enum_common_p(GETPROF(kattrs), cb, ctxt, pres,
189 wantattr, &cnt, profs);
190 }
191
192 if (res == 0 && wantattr)
193 res = cb(NULL, kattrs, ctxt, pres);
194
195 free_default_attrs(kattrs);
196 }
197
198 free_proflist(profs, cnt);
199
200 return (res);
201 }
202
203 /*
204 * Enumerate profiles with a username argument.
205 */
206 int
_enum_profs(const char * username,int (* cb)(const char *,kva_t *,void *,void *),void * ctxt,void * pres)207 _enum_profs(const char *username,
208 int (*cb)(const char *, kva_t *, void *, void *),
209 void *ctxt, void *pres)
210 {
211 return (_enum_common(username, cb, ctxt, pres, B_FALSE));
212 }
213
214 /*
215 * Enumerate attributes with a username argument.
216 */
217 int
_enum_attrs(const char * username,int (* cb)(const char *,kva_t *,void *,void *),void * ctxt,void * pres)218 _enum_attrs(const char *username,
219 int (*cb)(const char *, kva_t *, void *, void *),
220 void *ctxt, void *pres)
221 {
222 return (_enum_common(username, cb, ctxt, pres, B_TRUE));
223 }
224
225
226 /*
227 * Enumerate authorizations in the "auths" argument.
228 */
229 static int
_enum_auths_a(const char * cauths,int (* cb)(const char *,void *,void *),void * ctxt,void * pres)230 _enum_auths_a(const char *cauths, int (*cb)(const char *, void *, void *),
231 void *ctxt, void *pres)
232 {
233 char *auth, *last, *auths;
234 int res = 0;
235
236 if (cauths == NULL || cb == NULL)
237 return (0);
238
239 COPYTOSTACK(auths, cauths)
240
241 while (auth = strtok_r(auths, KV_SEPSTR, &last)) {
242 auths = NULL; /* For next iterations of strtok_r */
243
244 res = cb(auth, ctxt, pres);
245
246 if (res != 0)
247 return (res);
248 }
249 return (res);
250 }
251
252 /*
253 * Magic struct and function to allow using the _enum_attrs functions to
254 * enumerate the authorizations.
255 */
256 typedef struct ccomm2auth {
257 int (*cb)(const char *, void *, void *);
258 void *ctxt;
259 } ccomm2auth;
260
261 /*ARGSUSED*/
262 static int
comm2auth(const char * name,kva_t * attr,void * ctxt,void * pres)263 comm2auth(const char *name, kva_t *attr, void *ctxt, void *pres)
264 {
265 ccomm2auth *ca = ctxt;
266 char *auths;
267
268 /* Note: PROFATTR_AUTHS_KW is equal to USERATTR_AUTHS_KW */
269 auths = kva_match(attr, PROFATTR_AUTHS_KW);
270 return (_enum_auths_a(auths, ca->cb, ca->ctxt, pres));
271 }
272
273 /*
274 * Enumerate authorizations for username.
275 */
276 int
_enum_auths(const char * username,int (* cb)(const char *,void *,void *),void * ctxt,void * pres)277 _enum_auths(const char *username,
278 int (*cb)(const char *, void *, void *),
279 void *ctxt, void *pres)
280 {
281 ccomm2auth c2a;
282
283 if (cb == NULL)
284 return (-1);
285
286 c2a.cb = cb;
287 c2a.ctxt = ctxt;
288
289 return (_enum_common(username, comm2auth, &c2a, pres, B_TRUE));
290 }
291
292 int
_auth_match_noun(const char * pattern,const char * auth,size_t auth_len,const char * auth_noun)293 _auth_match_noun(const char *pattern, const char *auth,
294 size_t auth_len, const char *auth_noun)
295 {
296 size_t pattern_len;
297 char *grant;
298 char *pattern_noun;
299 char *slash;
300
301 pattern_len = strlen(pattern);
302 /*
303 * If the specified authorization has a trailing object
304 * and the current authorization we're checking also has
305 * a trailing object, the object names must match.
306 *
307 * If there is no object name failure, then we must
308 * check for an exact match of the two authorizations
309 */
310 if (auth_noun != NULL) {
311 if ((slash = strchr(pattern, KV_OBJECTCHAR)) != NULL) {
312 pattern_noun = slash + 1;
313 pattern_len -= strlen(slash);
314 if (strcmp(pattern_noun, auth_noun) != 0)
315 return (0);
316 } else if ((auth_len == pattern_len) &&
317 (strncmp(pattern, auth, pattern_len) == 0)) {
318 return (1);
319 }
320 }
321
322 /*
323 * If the wildcard is not in the last position in the string, don't
324 * match against it.
325 */
326 if (pattern[pattern_len-1] != KV_WILDCHAR)
327 return (0);
328
329 /*
330 * If the strings are identical up to the wildcard and auth does not
331 * end in "grant", then we have a match.
332 */
333 if (strncmp(pattern, auth, pattern_len - 1) == 0) {
334 grant = strrchr(auth, '.');
335 if (grant != NULL) {
336 if (strncmp(grant + 1, "grant", 5) != NULL)
337 return (1);
338 }
339 }
340 return (0);
341 }
342
343 int
_auth_match(const char * pattern,const char * auth)344 _auth_match(const char *pattern, const char *auth)
345 {
346 return (_auth_match_noun(pattern, auth, strlen(auth), NULL));
347 }
348
349 static int
_is_authorized(const char * auth,void * authname,void * res)350 _is_authorized(const char *auth, void *authname, void *res)
351 {
352 int *resp = res;
353 char *authname_noun;
354 char *slash;
355 size_t auth_len;
356 size_t noun_len;
357
358 auth_len = strlen(authname);
359 if ((slash = strchr(authname, KV_OBJECTCHAR)) != NULL) {
360 authname_noun = slash + 1;
361 noun_len = strlen(slash);
362 auth_len -= noun_len;
363 } else {
364 authname_noun = NULL;
365 }
366
367 if (strcmp(authname, auth) == 0) {
368 /* exact match, we're done */
369 *resp = 1;
370 return (1);
371 } else if (noun_len || strchr(auth, KV_WILDCHAR) != NULL) {
372 if (_auth_match_noun(auth, authname,
373 auth_len, authname_noun)) {
374 *resp = 1;
375 return (1);
376 }
377 }
378
379 return (0);
380 }
381
382 int
chkauthattr(const char * authname,const char * username)383 chkauthattr(const char *authname, const char *username)
384 {
385 int auth_granted = 0;
386
387 if (authname == NULL || username == NULL)
388 return (0);
389
390 (void) _enum_auths(username, _is_authorized, (char *)authname,
391 &auth_granted);
392
393 return (auth_granted);
394 }
395
396 #define CONSOLE_USER_LINK "/dev/vt/console_user"
397
398 static int
is_cons_user(const char * user)399 is_cons_user(const char *user)
400 {
401 struct stat cons;
402 struct passwd pw;
403 char pwbuf[NSS_BUFLEN_PASSWD];
404
405 if (user == NULL) {
406 return (0);
407 }
408 if (stat(CONSOLE_USER_LINK, &cons) == -1) {
409 return (0);
410 }
411 if (getpwnam_r(user, &pw, pwbuf, sizeof (pwbuf)) == NULL) {
412 return (0);
413 }
414
415 return (pw.pw_uid == cons.st_uid);
416 }
417
418 static void
free_default_attrs(kva_t * kva)419 free_default_attrs(kva_t *kva)
420 {
421 int i;
422
423 for (i = 0; i < kva->length; i++)
424 free(kva->data[i].value);
425
426 free(kva);
427 }
428
429 /*
430 * Return the default attributes; this are ignored when a STOP profile
431 * was found.
432 */
433 static kva_t *
get_default_attrs(const char * user)434 get_default_attrs(const char *user)
435 {
436 void *defp;
437 kva_t *kva;
438 int i;
439
440 kva = malloc(sizeof (kva_t) + sizeof (kv_t) * NDFLTPLY);
441
442 if (kva == NULL)
443 return (NULL);
444
445 kva->data = (kv_t *)(void *)&kva[1];
446 kva->length = 0;
447
448 if ((defp = defopen_r(AUTH_POLICY)) == NULL)
449 goto return_null;
450
451 for (i = is_cons_user(user) ? 0 : 1; i < NDFLTPLY; i++) {
452 char *cp = defread_r(dfltply[i].defkw, defp);
453
454 if (cp == NULL)
455 continue;
456 if ((cp = strdup(cp)) == NULL)
457 goto return_null;
458
459 kva->data[kva->length].key = dfltply[i].attr;
460 kva->data[kva->length++].value = cp;
461 }
462
463 (void) defclose_r(defp);
464 return (kva);
465
466 return_null:
467 if (defp != NULL)
468 (void) defclose_r(defp);
469
470 free_default_attrs(kva);
471 return (NULL);
472 }
473