Bug Summary

File:auth/auth.c
Location:line 458, column 7
Description:Branch condition evaluates to a garbage value

Annotated Source Code

1/* Authentication server.
2 Copyright (C) 1996,97,98,99,2002 Free Software Foundation, Inc.
3 Written by Roland McGrath.
4
5 This file is part of the GNU Hurd.
6
7 The GNU Hurd is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2, or (at
10 your option) any later version.
11
12 The GNU Hurd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
20
21#include <stddef.h>
22#include <stdlib.h>
23#include <string.h>
24#include <mach.h>
25#include <pthread.h>
26#include <hurd.h>
27#include <hurd/startup.h>
28#include <hurd/ports.h>
29#include <hurd/ihash.h>
30#include <idvec.h>
31#include <assert.h>
32#include <argp.h>
33#include <error.h>
34#include <version.h>
35#include "auth_S.h"
36#include "auth_reply_U.h"
37
38const char *argp_program_version = STANDARD_HURD_VERSION(auth)"auth" " (GNU Hurd) " "0.5";
39
40
41/* Auth handles are server ports with sets of ids. */
42struct authhandle
43 {
44 struct port_info pi;
45 struct idvec euids, egids, auids, agids;
46 };
47
48struct port_bucket *auth_bucket;
49struct port_class *authhandle_portclass;
50
51
52/* Create a new auth port. */
53
54static error_t
55create_authhandle (struct authhandle **new)
56{
57 error_t err = ports_create_port (authhandle_portclass, auth_bucket,
58 sizeof **new, new);
59 if (! err)
60 bzero (&(*new)->euids, (void *) &(*new)[1] - (void *) &(*new)->euids);
61 return err;
62}
63
64/* Clean up a dead auth port. */
65
66static void
67destroy_authhandle (void *p)
68{
69 struct authhandle *h = p;
70 idvec_free_contents (&h->euids);
71 idvec_free_contents (&h->egids);
72 idvec_free_contents (&h->auids);
73 idvec_free_contents (&h->agids);
74}
75
76/* Called by server stub functions. */
77
78authhandle_t
79auth_port_to_handle (auth_t auth)
80{
81 return ports_lookup_port (auth_bucket, auth, authhandle_portclass);
82}
83
84/* id management. */
85
86static inline void
87idvec_copyout (struct idvec *idvec, uid_t **ids, size_t *nids)
88{
89 if (idvec->num > *nids)
90 *ids = idvec->ids;
91 else
92 memcpy (*ids, idvec->ids, idvec->num * sizeof *ids);
93 *nids = idvec->num;
94}
95
96#define C(auth, ids)idvec_copyout (&auth->ids, ids, nids) idvec_copyout (&auth->ids, ids, n##ids)
97#define OUTIDS(auth)(idvec_copyout (&auth->euids, euids, neuids), idvec_copyout
(&auth->egids, egids, negids), idvec_copyout (&auth
->auids, auids, nauids), idvec_copyout (&auth->agids
, agids, nagids))
(C (auth, euids)idvec_copyout (&auth->euids, euids, neuids), C (auth, egids)idvec_copyout (&auth->egids, egids, negids), \
98 C (auth, auids)idvec_copyout (&auth->auids, auids, nauids), C (auth, agids)idvec_copyout (&auth->agids, agids, nagids))
99
100/* Implement auth_getids as described in <hurd/auth.defs>. */
101kern_return_t
102S_auth_getids (struct authhandle *auth,
103 uid_t **euids,
104 size_t *neuids,
105 uid_t **auids,
106 size_t *nauids,
107 uid_t **egids,
108 size_t *negids,
109 uid_t **agids,
110 size_t *nagids)
111{
112 if (! auth)
113 return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff));
114
115 OUTIDS (auth)(idvec_copyout (&auth->euids, euids, neuids), idvec_copyout
(&auth->egids, egids, negids), idvec_copyout (&auth
->auids, auids, nauids), idvec_copyout (&auth->agids
, agids, nagids))
;
116
117 return 0;
118}
119
120/* Implement auth_makeauth as described in <hurd/auth.defs>. */
121kern_return_t
122S_auth_makeauth (struct authhandle *auth,
123 mach_port_t *authpts, size_t nauths,
124 uid_t *euids, size_t neuids,
125 uid_t *auids, size_t nauids,
126 uid_t *egids, size_t negids,
127 uid_t *agids, size_t nagids,
128 mach_port_t *newhandle)
129{
130 struct authhandle *newauth, *auths[1 + nauths];
131 int hasroot = 0;
132 error_t err;
133 size_t i, j;
134
135 if (!auth)
136 return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff));
137
138 auths[0] = auth;
139
140 /* Fetch the auth structures for all the ports passed in. */
141 for (i = 0; i < nauths; i++)
142 auths[i + 1] = auth_port_to_handle (authpts[i]);
143
144 ++nauths;
145
146 /* Verify that the union of the handles passed in either contains euid 0
147 (root), or contains all the requested ids. */
148
149#define isuid(uid, auth)(idvec_contains (&(auth)->euids, uid) || idvec_contains
(&(auth)->auids, uid))
\
150 (idvec_contains (&(auth)->euids, uid) \
151 || idvec_contains (&(auth)->auids, uid))
152#define groupmember(gid, auth)(idvec_contains (&(auth)->egids, gid) || idvec_contains
(&(auth)->agids, gid))
\
153 (idvec_contains (&(auth)->egids, gid) \
154 || idvec_contains (&(auth)->agids, gid))
155#define isroot(auth)(idvec_contains (&(auth)->euids, 0) || idvec_contains (
&(auth)->auids, 0))
isuid (0, auth)(idvec_contains (&(auth)->euids, 0) || idvec_contains (
&(auth)->auids, 0))
156
157 for (i = 0; i < nauths; i++)
158 if (auths[i] && isroot (auths[i])(idvec_contains (&(auths[i])->euids, 0) || idvec_contains
(&(auths[i])->auids, 0))
)
159 {
160 hasroot = 1;
161 break;
162 }
163
164 if (!hasroot)
165 {
166 int has_it;
167
168 for (i = 0; i < neuids; i++)
169 {
170 has_it = 0;
171 for (j = 0; j < nauths; j++)
172 if (auths[j] && isuid (euids[i], auths[j])(idvec_contains (&(auths[j])->euids, euids[i]) || idvec_contains
(&(auths[j])->auids, euids[i]))
)
173 {
174 has_it = 1;
175 break;
176 }
177 if (!has_it)
178 goto eperm;
179 }
180
181 for (i = 0; i < nauids; i++)
182 {
183 has_it = 0;
184 for (j = 0; j < nauths; j++)
185 if (auths[j] && isuid (auids[i], auths[j])(idvec_contains (&(auths[j])->euids, auids[i]) || idvec_contains
(&(auths[j])->auids, auids[i]))
)
186 {
187 has_it = 1;
188 break;
189 }
190 if (!has_it)
191 goto eperm;
192 }
193
194 for (i = 0; i < negids; i++)
195 {
196 has_it = 0;
197 for (j = 0; j < nauths; j++)
198 if (auths[j] && groupmember (egids[i], auths[j])(idvec_contains (&(auths[j])->egids, egids[i]) || idvec_contains
(&(auths[j])->agids, egids[i]))
)
199 {
200 has_it = 1;
201 break;
202 }
203 if (!has_it)
204 goto eperm;
205 }
206
207 for (i = 0; i < nagids; i++)
208 {
209 has_it = 0;
210 for (j = 0; j < nauths; j++)
211 if (auths[j] && groupmember (agids[i], auths[j])(idvec_contains (&(auths[j])->egids, agids[i]) || idvec_contains
(&(auths[j])->agids, agids[i]))
)
212 {
213 has_it = 1;
214 break;
215 }
216 if (!has_it)
217 goto eperm;
218 }
219 }
220
221 err = create_authhandle (&newauth);
222
223 /* Create a new handle with the specified ids. */
224
225#define MERGES (euids); S (egids); S (auids); S (agids); S (euids); S (egids); S (auids); S (agids);
226#define S(uids) if (!err) err = idvec_merge_ids (&newauth->uids, uids, n##uids)
227
228 MERGES (euids); S (egids); S (auids); S (agids);;
229
230#undef S
231
232 if (! err)
233 {
234 for (j = 1; j < nauths; ++j)
235 mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), authpts[j - 1]);
236 *newhandle = ports_get_right (newauth);
237 ports_port_deref (newauth);
238 }
239
240 for (j = 1; j < nauths; j++)
241 if (auths[j])
242 ports_port_deref (auths[j]);
243 return err;
244
245 eperm:
246 for (j = 1; j < nauths; j++)
247 if (auths[j])
248 ports_port_deref (auths[j]);
249 return EPERM((0x10 << 26) | ((1) & 0x3fff));
250}
251
252/* Transaction handling. */
253
254/* Since the user is responsible for freeing the rendezvous port, it has to
255 * wait for the server to have finished transmitting uids.
256 *
257 * The server thus waits for the user to give it uids (unless it was already
258 * there), transmits them and provides the passthrough port.
259 *
260 * The user gives the uids and waits for the passthrough port from the server.
261 *
262 * If the user is early, it has to tell the server it arrived.
263 */
264
265/* A pending user. */
266struct pending_user
267 {
268 hurd_ihash_locp_t locp; /* Position in the pending_users ihash table. */
269 pthread_cond_t wakeup; /* The reader is blocked on this condition. */
270
271 /* The user's auth handle. */
272 struct authhandle *user;
273
274 /* The port to pass back to the user. */
275 mach_port_t passthrough;
276 };
277
278/* A pending server. */
279struct pending_server
280 {
281 hurd_ihash_locp_t locp; /* Position in the pending_servers ihash table. */
282 pthread_cond_t wakeup; /* The server is blocked on this condition. */
283 };
284
285/* Table of pending transactions keyed on RENDEZVOUS. */
286struct hurd_ihash pending_users
287 = HURD_IHASH_INITIALIZER (offsetof (struct pending_user, locp)){ .nr_items = 0, .size = 0, .cleanup = (hurd_ihash_cleanup_t)
0, .max_load = 80, .locp_offset = (__builtin_offsetof(struct
pending_user, locp))}
;
288struct hurd_ihash pending_servers
289 = HURD_IHASH_INITIALIZER (offsetof (struct pending_server, locp)){ .nr_items = 0, .size = 0, .cleanup = (hurd_ihash_cleanup_t)
0, .max_load = 80, .locp_offset = (__builtin_offsetof(struct
pending_server, locp))}
;
290pthread_mutex_t pending_lock = PTHREAD_MUTEX_INITIALIZER{ ((__pthread_spinlock_t) 0), ((__pthread_spinlock_t) 0), 0, 0
, 0, 0, 0, 0 }
;
291
292/* Implement auth_user_authenticate as described in <hurd/auth.defs>. */
293kern_return_t
294S_auth_user_authenticate (struct authhandle *userauth,
295 mach_port_t reply,
296 mach_msg_type_name_t reply_type,
297 mach_port_t rendezvous,
298 mach_port_t *newport,
299 mach_msg_type_name_t *newporttype)
300{
301 struct pending_server *s;
302 struct pending_user u;
303 error_t err;
304
305 if (! userauth)
306 return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff));
307
308 if (rendezvous == MACH_PORT_NULL((mach_port_t) 0) || rendezvous == MACH_PORT_DEAD((mach_port_t) ~0))
309 return EINVAL((0x10 << 26) | ((22) & 0x3fff));
310
311 u.user = userauth;
312 pthread_cond_init (&u.wakeup, NULL((void*)0));
313
314 pthread_mutex_lock (&pending_lock);
315
316 err = hurd_ihash_add (&pending_users, rendezvous, &u);
317 if (err) {
318 pthread_mutex_unlock (&pending_lock);
319 return err;
320 }
321
322 /* Give the server the auth port.
323 We need to add a ref in case the port dies. */
324 ports_port_ref (userauth);
325
326 /* Look for this rendezvous in the server list. */
327 s = hurd_ihash_find (&pending_servers, rendezvous);
328 if (s) {
329 /* Found it! */
330
331 /* Remove it from the pending list. */
332 hurd_ihash_locp_remove (&pending_servers, s->locp);
333
334 /* Tell it we eventually arrived. */
335 pthread_cond_signal (&s->wakeup);
336 }
337
338 ports_interrupt_self_on_port_death (userauth, rendezvous)ports_interrupt_self_on_notification (userauth, rendezvous, (
0100 + 010))
;
339 /* Wait for server answer. */
340 if (pthread_hurd_cond_wait_np (&u.wakeup, &pending_lock) &&
341 hurd_ihash_find (&pending_users, rendezvous))
342 /* We were interrupted; remove our record. */
343 {
344 hurd_ihash_locp_remove (&pending_users, u.locp);
345
346 /* Was it a normal interruption or did RENDEZVOUS die? */
347 mach_port_type_t type;
348 mach_port_type (mach_task_self ()((__mach_task_self_ + 0)), rendezvous, &type);
349 err = type & MACH_PORT_TYPE_DEAD_NAME((mach_port_type_t)(1 << ((((mach_port_right_t) 4))+16)
))
? EINVAL((0x10 << 26) | ((22) & 0x3fff)) : EINTR((0x10 << 26) | ((4) & 0x3fff));
350 }
351
352 pthread_mutex_unlock (&pending_lock);
353
354 if (! err)
355 {
356 /* Extract the port. */
357 *newport = u.passthrough;
358 *newporttype = MACH_MSG_TYPE_MOVE_SEND17;
359 mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), rendezvous);
360 }
361
362 return err;
363}
364
365/* Implement auth_server_authenticate as described in <hurd/auth.defs>. */
366kern_return_t
367S_auth_server_authenticate (struct authhandle *serverauth,
368 mach_port_t reply,
369 mach_msg_type_name_t reply_type,
370 mach_port_t rendezvous,
371 mach_port_t newport,
372 mach_msg_type_name_t newport_type,
373 uid_t **euids,
374 size_t *neuids,
375 uid_t **auids,
376 size_t *nauids,
377 uid_t **egids,
378 size_t *negids,
379 uid_t **agids,
380 size_t *nagids)
381{
382 struct pending_user *u;
383 struct authhandle *user;
384 error_t err;
1
Variable 'err' declared without an initial value
385
386 if (! serverauth)
2
Assuming 'serverauth' is non-null
3
Taking false branch
387 return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff));
388
389 if (rendezvous == MACH_PORT_NULL((mach_port_t) 0) || rendezvous == MACH_PORT_DEAD((mach_port_t) ~0))
4
Assuming 'rendezvous' is not equal to 0
5
Taking false branch
390 return EINVAL((0x10 << 26) | ((22) & 0x3fff));
391
392 pthread_mutex_lock (&pending_lock);
393
394 /* Look for this rendezvous in the user list. */
395 u = hurd_ihash_find (&pending_users, rendezvous);
396 if (! u)
6
Assuming 'u' is non-null
7
Taking false branch
397 {
398 /* User not here yet, have to wait for it. */
399 struct pending_server s;
400 pthread_cond_init (&s.wakeup, NULL((void*)0));
401 err = hurd_ihash_add (&pending_servers, rendezvous, &s);
402 if (! err)
403 {
404 ports_interrupt_self_on_port_death (serverauth, rendezvous)ports_interrupt_self_on_notification (serverauth, rendezvous,
(0100 + 010))
;
405 if (pthread_hurd_cond_wait_np (&s.wakeup, &pending_lock) &&
406 hurd_ihash_find (&pending_servers, rendezvous))
407 /* We were interrupted; remove our record. */
408 {
409 hurd_ihash_locp_remove (&pending_servers, s.locp);
410
411 /* Was it a normal interruption or did RENDEZVOUS die? */
412 mach_port_type_t type;
413 mach_port_type (mach_task_self ()((__mach_task_self_ + 0)), rendezvous, &type);
414 err = type & MACH_PORT_TYPE_DEAD_NAME((mach_port_type_t)(1 << ((((mach_port_right_t) 4))+16)
))
? EINVAL((0x10 << 26) | ((22) & 0x3fff)) : EINTR((0x10 << 26) | ((4) & 0x3fff));
415 }
416 else
417 {
418 u = hurd_ihash_find (&pending_users, rendezvous);
419 if (! u)
420 /* User still not here, odd! */
421 err = EINTR((0x10 << 26) | ((4) & 0x3fff));
422 }
423 }
424 }
425
426 if (u)
8
Taking true branch
427 {
428 error_t err2;
429
430 /* Remove it from the pending list. */
431 hurd_ihash_locp_remove (&pending_users, u->locp);
432
433 /* Found it! */
434 user = u->user;
435
436 pthread_mutex_unlock (&pending_lock);
437
438 /* Tell third party. */
439 err2 = auth_server_authenticate_reply (reply, reply_type, 0,
440 user->euids.ids, user->euids.num,
441 user->auids.ids, user->auids.num,
442 user->egids.ids, user->egids.num,
443 user->agids.ids, user->agids.num);
444
445 if (err2)
9
Assuming 'err2' is 0
10
Taking false branch
446 mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), reply);
447
448 pthread_mutex_lock (&pending_lock);
449
450 /* Give the user the new port and wake the RPC up. */
451 u->passthrough = newport;
452
453 pthread_cond_signal (&u->wakeup);
454 }
455
456 pthread_mutex_unlock (&pending_lock);
457
458 if (err)
11
Branch condition evaluates to a garbage value
459 return err;
460
461 ports_port_deref (user);
462 mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), rendezvous);
463 return MIG_NO_REPLY-305;
464}
465
466
467
468static int
469auth_demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp)
470{
471 extern int auth_server (mach_msg_header_t *inp, mach_msg_header_t *outp);
472 return (auth_server (inp, outp) ||
473 ports_interrupt_server (inp, outp) ||
474 ports_notify_server (inp, outp));
475}
476
477
478int
479main (int argc, char **argv)
480{
481 error_t err;
482 mach_port_t boot;
483 process_t proc;
484 mach_port_t hostpriv, masterdev;
485 struct authhandle *firstauth;
486 struct argp argp = { 0, 0, 0, "Hurd standard authentication server." };
487
488 argp_parse (&argp, argc, argv, 0, 0, 0);
489
490 auth_bucket = ports_create_bucket ();
491 authhandle_portclass = ports_create_class (&destroy_authhandle, 0);
492
493 /* Create the initial root auth handle. */
494 err = create_authhandle (&firstauth);
495 assert_perror (err)(!(err) ? (void) (0) : __assert_perror_fail ((err), "auth.c",
495, __PRETTY_FUNCTION__))
;
496 idvec_add (&firstauth->euids, 0);
497 idvec_add (&firstauth->auids, 0);
498 idvec_add (&firstauth->auids, 0);
499 idvec_merge (&firstauth->egids, &firstauth->euids);
500 idvec_merge (&firstauth->agids, &firstauth->auids);
501
502 /* Fetch our bootstrap port and contact the bootstrap filesystem. */
503 err = task_get_bootstrap_port (mach_task_self (), &boot)(task_get_special_port((((__mach_task_self_ + 0))), 4, (&
boot)))
;
504 assert_perror (err)(!(err) ? (void) (0) : __assert_perror_fail ((err), "auth.c",
504, __PRETTY_FUNCTION__))
;
505 if (boot == MACH_PORT_NULL((mach_port_t) 0))
506 error (2, 0, "auth server can only be run by init during boot");
507 err = startup_authinit (boot, ports_get_right (firstauth),
508 MACH_MSG_TYPE_MAKE_SEND20, &proc);
509 if (err)
510 error (2, err, "cannot contact init for bootstrap");
511
512 /* Register ourselves with the proc server and then start signals. */
513 proc_getprivports (proc, &hostpriv, &masterdev);
514 proc_register_version (proc, hostpriv, "auth", "", HURD_VERSION"0.5");
515 mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), masterdev);
516 _hurd_port_set (&_hurd_ports[INIT_PORT_PROC], proc);
517 _hurd_proc_init (argv, NULL((void*)0), 0);
518
519 /* Init knows intimately that we will be ready for messages
520 as soon as this returns. */
521 startup_essential_task (boot, mach_task_self ()((__mach_task_self_ + 0)), MACH_PORT_NULL((mach_port_t) 0), "auth",
522 hostpriv);
523 mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), boot);
524 mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), hostpriv);
525
526 /* Be a server. */
527 while (1)
528 ports_manage_port_operations_multithread (auth_bucket,
529 auth_demuxer,
530 30 * 1000, 0, 0);
531}