source: trunk/third/ammonite/libammonite/ammonite-general.c @ 15506

Revision 15506, 11.8 KB checked in by ghudson, 24 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r15505, which included commits to RCS files with non-trunk default branches.
Line 
1/* $Id: ammonite-general.c,v 1.1.1.1 2001-01-16 15:26:26 ghudson Exp $
2 *
3 * ammonite-general.c:
4 *
5 * General utility functions for using the Eazel ammonite authentication system.
6 *
7 * Copyright (C) 2000 Eazel, Inc
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public
20 * License along with this program; if not, write to the
21 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
23 *
24 * Author:  Michael Fleming <mfleming@eazel.com>
25 *
26 */
27
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif /* HAVE_CONFIG_H */
31
32#include "libammonite.h"
33#include <orb/orbit.h>
34#include <liboaf/liboaf.h>
35#include <stdlib.h>
36
37#ifdef DEBUG
38#define DEBUG_MSG(x) my_debug_printf x
39#include <stdio.h>
40
41static void
42my_debug_printf(char *fmt, ...)
43{
44        va_list args;
45        gchar * out;
46
47        g_assert (fmt);
48
49        va_start (args, fmt);
50
51        out = g_strdup_vprintf (fmt, args);
52
53        fprintf (stderr, "DEBUG: %s\n", out);
54
55        g_free (out);
56        va_end (args);
57}
58
59#else
60#define DEBUG_MSG(x)
61#endif /* DEBUG */
62
63/*
64 * Global Variables
65 */
66
67static EazelProxy_UserControl gl_user_control = CORBA_OBJECT_NIL;
68static PortableServer_POA gl_poa = CORBA_OBJECT_NIL;
69
70/*
71 * EazelProxy_User extention functions
72 */
73void
74EazelProxy_User_copy (EazelProxy_User *dest, const EazelProxy_User *src)
75{
76        g_assert (src);
77        g_assert (dest);
78
79        dest->user_name = CORBA_string_dup (src->user_name);
80        dest->login_state = src->login_state;
81        dest->proxy_port = src->proxy_port;
82        dest->is_default = src->is_default;
83        dest->services_redirect_uri = CORBA_string_dup (src->services_redirect_uri);
84        dest->services_login_path = CORBA_string_dup (src->services_login_path);
85        dest->login_http_response = CORBA_string_dup (src->login_http_response);
86}
87
88
89EazelProxy_User *
90EazelProxy_User_duplicate (const EazelProxy_User *original )
91{
92        EazelProxy_User *ret;
93
94        if ( NULL == original ) {
95                return NULL;
96        }
97
98        ret = EazelProxy_User__alloc();
99
100        EazelProxy_User_copy (ret, original);
101
102        return ret;
103}
104
105
106void
107EazelProxy_AuthnFailInfo_copy (EazelProxy_AuthnFailInfo *dest, const EazelProxy_AuthnFailInfo *src)
108{
109        g_assert (src);
110        g_assert (dest);
111
112        dest->code = src->code;
113        dest->http_result = CORBA_string_dup (src->http_result);
114}
115
116EazelProxy_AuthnFailInfo *
117EazelProxy_AuthnFailInfo_duplicate (const EazelProxy_AuthnFailInfo *original)
118{
119        EazelProxy_AuthnFailInfo *ret;
120
121        if ( NULL == original ) {
122                return NULL;
123        }
124
125        ret = EazelProxy_AuthnFailInfo__alloc();
126
127        EazelProxy_AuthnFailInfo_copy (ret, original);
128
129        return ret;
130}
131
132/*
133 * Utility Functions
134 */
135
136
137void
138ammonite_url_free (AmmoniteParsedURL * to_free)
139{
140        if ( NULL != to_free ) {
141                g_free (to_free->scheme);
142                g_free (to_free->user);
143                g_free (to_free->realm);
144                g_free (to_free->resource);
145                g_free (to_free);
146        }
147}
148
149/* {scheme}://user@realm/<resource>                     */
150/* {scheme}:/<resource> means 'default user and realm'  */
151
152AmmoniteParsedURL *
153ammonite_url_parse (const char *url)
154{
155        const char *scheme;
156        const char *current;
157        AmmoniteParsedURL *result;
158        gboolean success;
159
160        g_return_val_if_fail ( NULL != url, NULL);
161
162        success = FALSE;
163        current = url;
164        result = g_new0 (AmmoniteParsedURL, 1);
165
166        /* ([^:]*):/(/(([^@]+)(@([^/]*))?)?/)?(.*)
167         *          ^        ^            ^ resource
168         *          user     realm
169         *   ^ scheme
170         */
171
172        /* Scheme portion */
173        scheme = url;
174        current = strchr (current, (unsigned char)':');
175
176        if (NULL == current) {
177                success = FALSE;
178                goto error;
179        }
180
181        current++;
182        result->scheme = g_strndup (url, current - scheme);
183
184        /* User portion */
185
186        if ( '\0' == *current || '/' != *current ) {
187                success = FALSE;
188                goto error;
189        }
190
191        if ( '/' == *(current+1) && '/' == *(current+2) ) {
192                current+=2;
193        } else if ( '/' == *(current+1) ) {
194                const char *user;
195
196                current += 2;
197                user = current;
198
199                while ( '\0' != *current && '@' != *current && '/' != *current ) {
200                        current++;
201                }
202
203                if ( current == user ) {
204                        /* allow empty resource */
205                        success = TRUE;
206                        result->resource = g_strdup ("/");
207                        goto error;
208                }
209
210                result->user = g_strndup (user, current - user);
211                user = NULL;
212
213                if ( '\0' == *current ) {
214                        /* allow empty resource */
215                        success = TRUE;
216                        result->resource = g_strdup ("/");
217                        goto error;
218                }
219               
220                if ( '@' == *current ) {
221                        const char *realm;
222                       
223                        realm = ++current;
224
225                        while ( '\0' != *current && '/' != *current ) {
226                                current++;
227                        }
228
229                        if ( '\0' == *current || current == realm ) {
230                                /* allow empty resource */
231                                success = TRUE;
232                                result->resource = g_strdup ("/");
233                                goto error;
234                        }
235                       
236                        result->realm = g_strndup (realm, current-realm);
237
238                        g_assert ('/' == *current);
239                }
240        }
241
242        result->resource = g_strdup (current);
243
244        success = TRUE;
245error:
246
247        if ( ! success ) {
248                ammonite_url_free (result);
249                return NULL;
250        } else {
251                return result;
252        }
253}
254
255/* scheme should have trailing colon */
256static char *
257make_new_uri (const char * scheme, EazelProxy_User *user_info, const AmmoniteParsedURL *parsed)
258{
259        g_return_val_if_fail ( NULL != user_info, NULL );
260        g_return_val_if_fail ( NULL != parsed, NULL );
261
262        if (EazelProxy_AUTHENTICATED == user_info->login_state
263            && 0 != user_info->proxy_port
264        ) {
265                return g_strdup_printf ("%s//localhost:%d%s",
266                                scheme, user_info->proxy_port, parsed->resource );
267        } else {
268                return NULL;
269        }
270}
271
272/* FIXME: bugzilla.eazel.com 2850: should cache the result and follow with a Listener */
273/* FIXME: bugzilla.eazel.com 2850: should support realms */
274static EazelProxy_User *
275usercontrol_find_user (const char *user, const char *realm)
276{
277        CORBA_Environment ev;
278        EazelProxy_User *ret = NULL;
279        EazelProxy_UserList *userlist = NULL;
280        CORBA_unsigned_long i;
281
282        CORBA_exception_init (&ev);
283
284        userlist = EazelProxy_UserControl_get_active_users (gl_user_control, &ev);
285
286        if ( NULL == userlist || CORBA_NO_EXCEPTION != ev._major ) {
287                goto error;
288        }
289
290        for (i = 0 ; i < userlist->_length ; i++ ) {
291                EazelProxy_User *current;
292
293                current = userlist->_buffer + i;
294                if ( NULL != current->user_name
295                        && 0 == strcmp (current->user_name, user)
296                ) {
297                        ret = EazelProxy_User_duplicate (current);
298                        break;
299                }
300        }
301
302error:
303        CORBA_free (userlist);
304        CORBA_exception_free (&ev);
305
306        return ret;
307}
308
309/*
310 * Public Library Functions
311 */
312
313
314gboolean
315ammonite_init (PortableServer_POA poa)
316{
317        gboolean ret;
318        CORBA_Environment ev;
319
320        CORBA_exception_init (&ev);
321
322        gl_poa = poa;
323        gl_user_control = (EazelProxy_UserControl) oaf_activate_from_id (IID_EAZELPROXY, 0, NULL, &ev);
324
325        ret = (CORBA_NO_EXCEPTION == ev._major);
326
327        CORBA_exception_free (&ev);
328
329        return ret;
330}
331
332void
333ammonite_shutdown (void)
334{
335        CORBA_Environment ev;
336
337        CORBA_exception_init (&ev);
338       
339        if (CORBA_OBJECT_NIL != gl_user_control) {
340                CORBA_Object_release (gl_user_control, &ev);
341        }
342
343        CORBA_exception_free (&ev);
344}
345
346EazelProxy_UserControl
347ammonite_get_user_control (void)
348{
349        return gl_user_control;
350}
351
352PortableServer_POA
353ammonite_get_poa (void)
354{
355        return gl_poa;
356}
357
358/* FIXME respawn/reconnect to ammonite when it goes away */
359AmmoniteError
360ammonite_http_url_for_eazel_url (const char *orig_url, /* OUT */ char ** new_url)
361{
362        AmmoniteParsedURL *parsed       = NULL;
363        EazelProxy_User *user_info      = NULL;
364        char *ret                       = NULL;
365        AmmoniteError err               = ERR_Success;
366        CORBA_Environment ev;
367
368        g_return_val_if_fail (NULL != new_url, EAZELPROXY_AUTHN_FAIL_ARG_INVALID);
369        g_return_val_if_fail (NULL != orig_url, EAZELPROXY_AUTHN_FAIL_ARG_INVALID);
370        g_return_val_if_fail (CORBA_OBJECT_NIL != gl_user_control, EAZELPROXY_AUTHN_FAIL_ARG_INVALID);
371
372
373        *new_url = NULL;
374
375        CORBA_exception_init (&ev);
376       
377        parsed = ammonite_url_parse (orig_url);
378        if ( NULL == parsed ) {
379                ret = NULL;
380                err = ERR_BadURL;
381                goto error;
382        }
383
384        /* Use the default user? */
385        if (NULL == parsed->user) {
386                user_info = EazelProxy_UserControl_get_default_user (gl_user_control, &ev);
387                if (CORBA_USER_EXCEPTION == ev._major) {
388                        err = ERR_UserNotLoggedIn;
389                        user_info = NULL;
390                } else if (CORBA_SYSTEM_EXCEPTION == ev._major) {
391                        err = ERR_CORBA;
392                        user_info = NULL;
393                }
394
395        } else {
396                /* A user was specified in the URL */
397                user_info = usercontrol_find_user (parsed->user, parsed->realm);
398                if ( NULL == user_info) {
399                        err = ERR_UserNotLoggedIn;
400                }
401        }
402
403        if ( NULL == user_info ) {
404                ret = NULL;
405                g_assert (err != ERR_Success);
406        } else {
407                ret = make_new_uri (":", user_info, parsed);
408        }
409
410        CORBA_free (user_info);
411        user_info = NULL;
412
413        *new_url = ret;
414        ret = NULL;     
415error:
416        ammonite_url_free (parsed);
417        CORBA_exception_free (&ev);
418
419        return err;
420}
421
422static gboolean
423is_http_localhost (const char *uri, /*OUT*/ unsigned *p_port,  /*OUT*/ const char ** p_path)
424{
425        static const char * uri_prefix_1 = "http://localhost:";
426        static const char * uri_prefix_2 = "http://127.0.0.1:";
427
428        const char * port_marker;
429        const char * port_end;
430
431        *p_port = 0;
432        *p_path = NULL;
433
434        if (NULL == uri) {
435                return FALSE;
436        }
437
438        if (0 == strncmp (uri, uri_prefix_1, strlen (uri_prefix_1))) {
439                port_marker = uri +strlen (uri_prefix_1);
440        } else if (0 == strncmp (uri, uri_prefix_1, strlen (uri_prefix_2))) {
441                port_marker = uri +strlen (uri_prefix_2);
442        } else {
443                return FALSE;
444        }
445
446        *p_port = strtoul (port_marker, (char **)&port_end, 10);
447
448        if (NULL == port_end) {
449                return FALSE;
450        }
451
452        *p_path = port_end;
453
454        return TRUE;
455}
456
457AmmoniteError
458ammonite_eazel_url_for_http_url (const char *orig_url, /* OUT */ char ** p_new_url)
459{
460        unsigned port;
461        const char *path;
462        EazelProxy_UserList *users;
463        CORBA_Environment ev;
464        CORBA_unsigned_long i;
465        EazelProxy_User *cur;
466
467        CORBA_exception_init (&ev);
468
469        *p_new_url = NULL;
470
471        if ( ! is_http_localhost (orig_url, &port, &path)) {
472                return ERR_BadURL;
473        }
474       
475        /* FIXME this is really inefficient.  I should keep this list
476         * locally and update via UserListener
477         */
478
479        users = EazelProxy_UserControl_get_active_users (gl_user_control, &ev);
480
481        if (CORBA_NO_EXCEPTION != ev._major) {
482                CORBA_exception_free (&ev);
483                return ERR_CORBA;
484        }
485
486
487        for (i = 0; i < users->_length ; i++) {
488                cur = users->_buffer + i;
489
490                if (cur->proxy_port == port) {
491                        break;
492                }
493        }
494
495        if (i < users->_length) {
496                if (cur->is_default) {
497                        *p_new_url = g_strconcat ("eazel-services://", path, NULL);
498                } else {
499                        *p_new_url = g_strconcat ("eazel-services://",
500                                                        cur->user_name, path, NULL);
501                }
502
503        } else {
504                CORBA_free (users);
505                return ERR_UserNotLoggedIn;
506        }
507
508        CORBA_free (users);
509        CORBA_exception_free (&ev);
510
511        return ERR_Success;
512}
513
514const char *
515ammonite_fail_code_to_string (CORBA_long code)
516{
517
518        static const char * fail_code_strings[] = {
519                "(invalid)",
520                "Argument Invalid",
521                "User Exists",
522                "Insufficient Resources",
523                "Authentication Failure",
524                "Network Error",
525                "Unexpected Server Response",
526                "User Canceled"
527        };
528
529        if (code >= 0 && code <= (sizeof (fail_code_strings) / sizeof (fail_code_strings[0]))) {
530                return fail_code_strings [code];
531        }
532
533        return "(unknown)";
534}
535
536/*
537 * ammonite_get_default_user_username
538 *
539 * Returns username of the currently logged-in default Eazel Service User
540 * or NULL if there isn't one
541 */
542
543char *
544ammonite_get_default_user_username (EazelProxy_UserControl user_control)
545{
546        CORBA_Environment       ev;
547        EazelProxy_User         *user;
548        char *                  ret = NULL;
549
550        CORBA_exception_init (&ev);
551
552        if (CORBA_OBJECT_NIL != user_control) {
553
554                user = EazelProxy_UserControl_get_default_user (user_control, &ev);
555
556                if (CORBA_NO_EXCEPTION != ev._major) {
557                        DEBUG_MSG (("No Eazel Service User is currently logged in"));
558                        ret = NULL;
559                } else {
560                        DEBUG_MSG (("Default Eazel Service User is '%s'", user->user_name));
561                        ret = g_strdup (user->user_name);
562                        CORBA_free (user);
563                }
564        }
565
566        CORBA_exception_free (&ev);
567        return ret;
568}
Note: See TracBrowser for help on using the repository browser.