SoupAuthManagerNTLM: fix don't-fallback-to-Basic code
[platform/upstream/libsoup.git] / libsoup / soup-auth-manager-ntlm.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * soup-auth-manager-ntlm.c: NTLM auth manager
4  *
5  * Copyright (C) 2001-2007 Novell, Inc.
6  * Copyright (C) 2008 Red Hat, Inc.
7  */
8
9 #ifdef HAVE_CONFIG_H
10 #include <config.h>
11 #endif
12
13 #include <ctype.h>
14 #include <string.h>
15 #include <glib.h>
16
17 #ifdef USE_NTLM_AUTH
18 #include <stdlib.h>
19 #include <errno.h>
20 #endif
21 #include "soup-auth-manager-ntlm.h"
22 #include "soup-auth-ntlm.h"
23 #include "soup-message.h"
24 #include "soup-message-private.h"
25 #include "soup-misc.h"
26 #include "soup-session.h"
27 #include "soup-session-feature.h"
28 #include "soup-uri.h"
29
30 static void soup_auth_manager_ntlm_session_feature_init (SoupSessionFeatureInterface *feature_interface, gpointer interface_data);
31 static SoupSessionFeatureInterface *soup_auth_manager_parent_feature_interface;
32
33 static void attach (SoupSessionFeature *feature, SoupSession *session);
34 static void request_queued (SoupSessionFeature *feature, SoupSession *session,
35                             SoupMessage *msg);
36 static void request_started (SoupSessionFeature *feature, SoupSession *session,
37                              SoupMessage *msg, SoupSocket *socket);
38 static void request_unqueued (SoupSessionFeature *feature,
39                               SoupSession *session, SoupMessage *msg);
40 static gboolean add_feature (SoupSessionFeature *feature, GType type);
41 static gboolean remove_feature (SoupSessionFeature *feature, GType type);
42 static gboolean has_feature (SoupSessionFeature *feature, GType type);
43
44 G_DEFINE_TYPE_WITH_CODE (SoupAuthManagerNTLM, soup_auth_manager_ntlm, SOUP_TYPE_AUTH_MANAGER,
45                          G_IMPLEMENT_INTERFACE (SOUP_TYPE_SESSION_FEATURE,
46                                                 soup_auth_manager_ntlm_session_feature_init))
47
48 typedef enum {
49         SOUP_NTLM_NEW,
50 #ifdef USE_NTLM_AUTH
51         SOUP_NTLM_SENT_SSO_REQUEST,
52         SOUP_NTLM_RECEIVED_SSO_CHALLENGE,
53         SOUP_NTLM_SENT_SSO_RESPONSE,
54         SOUP_NTLM_SSO_FAILED,
55 #endif
56         SOUP_NTLM_SENT_REQUEST,
57         SOUP_NTLM_RECEIVED_CHALLENGE,
58         SOUP_NTLM_SENT_RESPONSE,
59         SOUP_NTLM_FAILED
60 } SoupNTLMState;
61
62 typedef struct {
63         SoupSocket *socket;
64         SoupNTLMState state;
65         char *response_header;
66
67         char *nonce, *domain;
68         SoupAuth *auth;
69 #ifdef USE_NTLM_AUTH
70         char *challenge_header;
71         int fd_in;
72         int fd_out;
73 #endif
74 } SoupNTLMConnection;
75
76 typedef struct {
77         gboolean use_ntlm;
78
79         SoupSession *session;
80         GHashTable *connections_by_msg;
81         GHashTable *connections_by_id;
82 #ifdef USE_NTLM_AUTH
83         gboolean ntlm_auth_accessible;
84 #endif
85 } SoupAuthManagerNTLMPrivate;
86 #define SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_AUTH_MANAGER_NTLM, SoupAuthManagerNTLMPrivate))
87
88 static char     *soup_ntlm_request         (void);
89 static gboolean  soup_ntlm_parse_challenge (const char  *challenge,
90                                             char       **nonce,
91                                             char       **default_domain);
92 static char     *soup_ntlm_response        (const char  *nonce, 
93                                             const char  *user,
94                                             const char  *password,
95                                             const char  *host, 
96                                             const char  *domain);
97 #ifdef USE_NTLM_AUTH
98 static void sso_ntlm_close (SoupNTLMConnection *conn);
99 #endif
100
101 static void
102 soup_auth_manager_ntlm_init (SoupAuthManagerNTLM *ntlm)
103 {
104         SoupAuthManagerNTLMPrivate *priv =
105                 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (ntlm);
106
107         priv->connections_by_id = g_hash_table_new (NULL, NULL);
108         priv->connections_by_msg = g_hash_table_new (NULL, NULL);
109 #ifdef USE_NTLM_AUTH
110         priv->ntlm_auth_accessible = (access (NTLM_AUTH, X_OK) == 0);
111 #endif
112 }
113
114 static void
115 free_ntlm_connection (SoupNTLMConnection *conn)
116 {
117         g_free (conn->response_header);
118         g_free (conn->nonce);
119         g_free (conn->domain);
120         if (conn->auth)
121                 g_object_unref (conn->auth);
122 #ifdef USE_NTLM_AUTH
123         g_free (conn->challenge_header);
124         sso_ntlm_close (conn);
125 #endif
126         g_slice_free (SoupNTLMConnection, conn);
127 }
128
129 static void
130 free_ntlm_connection_foreach (gpointer key, gpointer value, gpointer user_data)
131 {
132         free_ntlm_connection (value);
133 }
134
135 static void
136 finalize (GObject *object)
137 {
138         SoupAuthManagerNTLMPrivate *priv =
139                 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (object);
140
141         g_hash_table_foreach (priv->connections_by_id,
142                               free_ntlm_connection_foreach, NULL);
143         g_hash_table_destroy (priv->connections_by_id);
144         g_hash_table_destroy (priv->connections_by_msg);
145
146         G_OBJECT_CLASS (soup_auth_manager_ntlm_parent_class)->finalize (object);
147 }
148
149 static void
150 soup_auth_manager_ntlm_class_init (SoupAuthManagerNTLMClass *auth_manager_ntlm_class)
151 {
152         GObjectClass *object_class = G_OBJECT_CLASS (auth_manager_ntlm_class);
153
154         g_type_class_add_private (auth_manager_ntlm_class, sizeof (SoupAuthManagerNTLMPrivate));
155
156         object_class->finalize = finalize;
157 }
158
159 static void
160 soup_auth_manager_ntlm_session_feature_init (SoupSessionFeatureInterface *feature_interface,
161                                              gpointer interface_data)
162 {
163         soup_auth_manager_parent_feature_interface =
164                 g_type_interface_peek_parent (feature_interface);
165
166         feature_interface->attach = attach;
167         feature_interface->request_queued = request_queued;
168         feature_interface->request_started = request_started;
169         feature_interface->request_unqueued = request_unqueued;
170         feature_interface->add_feature = add_feature;
171         feature_interface->remove_feature = remove_feature;
172         feature_interface->has_feature = has_feature;
173 }
174
175 static void
176 attach (SoupSessionFeature *manager, SoupSession *session)
177 {
178         SoupAuthManagerNTLMPrivate *priv =
179                 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (manager);
180
181         /* FIXME: should support multiple sessions */
182         priv->session = session;
183
184         soup_auth_manager_parent_feature_interface->attach (manager, session);
185 }
186
187 static void
188 delete_conn (SoupSocket *socket, gpointer user_data)
189 {
190         SoupAuthManagerNTLMPrivate *priv = user_data;
191         SoupNTLMConnection *conn;
192
193         conn = g_hash_table_lookup (priv->connections_by_id, socket);
194         if (conn)
195                 free_ntlm_connection (conn);
196         g_hash_table_remove (priv->connections_by_id, socket);
197         g_signal_handlers_disconnect_by_func (socket, delete_conn, priv);
198 }
199
200 static SoupNTLMConnection *
201 get_connection (SoupAuthManagerNTLMPrivate *priv, SoupSocket *socket)
202 {
203         SoupNTLMConnection *conn;
204
205         conn = g_hash_table_lookup (priv->connections_by_id, socket);
206         if (conn)
207                 return conn;
208
209         conn = g_slice_new0 (SoupNTLMConnection);
210         conn->socket = socket;
211         conn->state = SOUP_NTLM_NEW;
212 #ifdef USE_NTLM_AUTH
213         conn->fd_in = -1;
214         conn->fd_out = -1;
215 #endif
216         g_hash_table_insert (priv->connections_by_id, socket, conn);
217
218         g_signal_connect (socket, "disconnected",
219                           G_CALLBACK (delete_conn), priv);
220         return conn;
221 }
222
223 static void
224 unset_conn (SoupMessage *msg, gpointer user_data)
225 {
226         SoupAuthManagerNTLMPrivate *priv = user_data;
227
228         g_hash_table_remove (priv->connections_by_msg, msg);
229         g_signal_handlers_disconnect_by_func (msg, unset_conn, priv);
230 }
231
232 static SoupNTLMConnection *
233 set_connection_for_msg (SoupAuthManagerNTLMPrivate *priv, SoupMessage *msg,
234                         SoupNTLMConnection *conn)
235 {
236         if (!g_hash_table_lookup (priv->connections_by_msg, msg)) {
237                 g_signal_connect (msg, "finished",
238                                   G_CALLBACK (unset_conn), priv);
239                 g_signal_connect (msg, "restarted",
240                                   G_CALLBACK (unset_conn), priv);
241         }
242         g_hash_table_insert (priv->connections_by_msg, msg, conn);
243
244         return conn;
245 }
246
247 static SoupNTLMConnection *
248 get_connection_for_msg (SoupAuthManagerNTLMPrivate *priv, SoupMessage *msg)
249 {
250         return g_hash_table_lookup (priv->connections_by_msg, msg);
251 }
252
253 #ifdef USE_NTLM_AUTH
254 static void
255 sso_ntlm_close (SoupNTLMConnection *conn)
256 {
257         if (conn->fd_in != -1) {
258                 close (conn->fd_in);
259                 conn->fd_in = -1;
260         }
261
262         if (conn->fd_out != -1) {
263                 close (conn->fd_out);
264                 conn->fd_out = -1;
265         }
266 }
267
268 static gboolean
269 sso_ntlm_initiate (SoupNTLMConnection *conn, SoupAuthManagerNTLMPrivate *priv)
270 {
271         char *username = NULL, *slash, *domain = NULL;
272         char *argv[9];
273         gboolean ret;
274
275         /* Return if ntlm_auth execution process exist already */
276         if (conn->fd_in != -1 && conn->fd_out != -1)
277                 return TRUE;
278         else
279                 /* Clean all sso data before re-initiate */
280                 sso_ntlm_close (conn);
281
282         if (!priv->ntlm_auth_accessible)
283                 goto done;
284
285         username = getenv ("NTLMUSER");
286         if (!username)
287                 username = getenv ("USER");
288         if (!username)
289                 goto done;
290
291         slash = strpbrk (username, "\\/");
292         if (slash) {
293                 domain = g_strdup (username);
294                 slash = domain + (slash - username);
295                 *slash = '\0';
296                 username = slash + 1;
297         }
298
299         argv[0] = NTLM_AUTH;
300         argv[1] = "--helper-protocol";
301         argv[2] = "ntlmssp-client-1";
302         argv[3] = "--use-cached-creds";
303         argv[4] = "--username";
304         argv[5] = username;
305         argv[6] = domain ? "--domain" : NULL;
306         argv[7] = domain;
307         argv[8] = NULL;
308         /* Spawn child process */
309         ret = g_spawn_async_with_pipes (NULL, argv, NULL,
310                                         G_SPAWN_FILE_AND_ARGV_ZERO,
311                                         NULL, NULL,
312                                         NULL, &conn->fd_in, &conn->fd_out,
313                                         NULL, NULL);
314         if (!ret)
315                 goto done;
316         g_free (domain);
317         return TRUE;
318 done:
319         g_free (domain);
320         return FALSE;
321 }
322
323 static char *
324 sso_ntlm_response (SoupNTLMConnection *conn, const char *input, SoupNTLMState conn_state)
325 {
326         ssize_t size;
327         char buf[1024], *response = NULL;
328         char *tmpbuf = buf;
329         size_t  len_in = strlen (input), len_out = sizeof (buf);
330
331         while (len_in > 0) {
332                 int written = write (conn->fd_in, input, len_in);
333                 if (written == -1) {
334                         /* Interrupted by a signal, retry it */
335                         if (errno == EINTR)
336                                 continue;
337                         /* write failed if other errors happen */
338                         goto done;
339                 }
340                 input += written;
341                 len_in -= written;
342         }
343         /* Read one line */
344         while (len_out > 0) {
345                 size = read (conn->fd_out, tmpbuf, len_out);
346                 if (size == -1) {
347                         if (errno == EINTR)
348                                 continue;
349                         goto done;
350                 } else if (size == 0)
351                         goto done;
352                 else if (tmpbuf[size - 1] == '\n') {
353                         tmpbuf[size - 1] = '\0';
354                         goto wrfinish;
355                 }
356                 tmpbuf += size;
357                 len_out -= size;
358         }
359         goto done;
360 wrfinish:
361         if (conn_state == SOUP_NTLM_NEW &&
362             g_ascii_strcasecmp (buf, "PW") == 0) {
363                 /* Samba/winbind installed but not configured */
364                 response = g_strdup ("PW");
365                 goto done;
366         }
367         if (conn_state == SOUP_NTLM_NEW &&
368             g_ascii_strncasecmp (buf, "YR ", 3) != 0)
369                 /* invalid response for type 1 message */
370                 goto done;
371         if (conn_state == SOUP_NTLM_RECEIVED_SSO_CHALLENGE &&
372             g_ascii_strncasecmp (buf, "KK ", 3) != 0 &&
373             g_ascii_strncasecmp (buf, "AF ", 3) != 0)
374                 /* invalid response for type 3 message */
375                 goto done;
376
377         response = g_strdup_printf ("NTLM %.*s", (int)(size - 4), buf + 3);
378         goto done;
379 done:
380         return response;
381 }
382 #endif /* USE_NTLM_AUTH */
383
384 static void
385 ntlm_authorize_pre (SoupMessage *msg, gpointer ntlm)
386 {
387         SoupAuthManagerNTLMPrivate *priv =
388                 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (ntlm);
389         SoupNTLMConnection *conn;
390         const char *val;
391         char *challenge = NULL;
392         SoupURI *uri;
393
394         conn = get_connection_for_msg (priv, msg);
395         if (!conn)
396                 return;
397
398         val = soup_message_headers_get_list (msg->response_headers,
399                                              "WWW-Authenticate");
400         if (!val)
401                 return;
402         challenge = soup_auth_manager_extract_challenge (val, "NTLM");
403         if (!challenge)
404                 return;
405
406         if (conn->state > SOUP_NTLM_SENT_REQUEST) {
407                 /* We already authenticated, but then got another 401.
408                  * That means "permission denied", so don't try to
409                  * authenticate again.
410                  */
411                 conn->state = SOUP_NTLM_FAILED;
412                 goto done;
413         }
414
415         if (!soup_ntlm_parse_challenge (challenge, &conn->nonce, &conn->domain)) {
416                 conn->state = SOUP_NTLM_FAILED;
417                 goto done;
418         }
419
420         conn->auth = soup_auth_ntlm_new (conn->domain,
421                                          soup_message_get_uri (msg)->host);
422 #ifdef USE_NTLM_AUTH
423         conn->challenge_header = g_strdup (challenge + 5);
424         if (conn->state == SOUP_NTLM_SENT_SSO_REQUEST) {
425                 conn->state = SOUP_NTLM_RECEIVED_SSO_CHALLENGE;
426                 goto done;
427         }
428 #endif
429         conn->state = SOUP_NTLM_RECEIVED_CHALLENGE;
430
431         uri = soup_message_get_uri (msg);
432         if (uri->password)
433                 soup_auth_authenticate (conn->auth, uri->user, uri->password);
434         else {
435                 soup_auth_manager_emit_authenticate (SOUP_AUTH_MANAGER (ntlm),
436                                                      msg, conn->auth, FALSE);
437         }
438
439  done:
440         g_free (challenge);
441
442         /* Remove the WWW-Authenticate headers so the session won't try
443          * to do Basic auth too.
444          */
445         soup_message_headers_remove (msg->response_headers, "WWW-Authenticate");
446 }
447
448 static void
449 ntlm_authorize_post (SoupMessage *msg, gpointer ntlm)
450 {
451         SoupAuthManagerNTLMPrivate *priv =
452                 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (ntlm);
453         SoupNTLMConnection *conn;
454         const char *username = NULL, *password = NULL;
455         char *slash, *domain = NULL;
456         SoupMessageFlags flags;
457
458         conn = get_connection_for_msg (priv, msg);
459         if (!conn || !conn->auth)
460                 return;
461
462 #ifdef USE_NTLM_AUTH
463         if (conn->state == SOUP_NTLM_RECEIVED_SSO_CHALLENGE) {
464                 char *input;
465                 input = g_strdup_printf ("TT %s\n", conn->challenge_header);
466                 /* Re-Initiate ntlm_auth process in case it was closed/killed abnormally */
467                 if (sso_ntlm_initiate (conn, priv)) {
468                         conn->response_header = sso_ntlm_response (conn,
469                                                                    input,
470                                                                    conn->state);
471                         /* Close ntlm_auth as it is no longer needed for current connection */
472                         sso_ntlm_close (conn);
473                         if (!conn->response_header) {
474                                 g_free (input);
475                                 goto ssofailure;
476                         }
477                         soup_session_requeue_message (priv->session, msg);
478                         g_free (input);
479                         goto done;
480                 }
481 ssofailure:
482                 conn->state = SOUP_NTLM_SSO_FAILED;
483                 soup_session_requeue_message (priv->session, msg);
484                 goto done;
485         }
486 #endif
487         username = soup_auth_ntlm_get_username (conn->auth);
488         password = soup_auth_ntlm_get_password (conn->auth);
489         if (!username || !password)
490                 goto done;
491
492         slash = strpbrk (username, "\\/");
493         if (slash) {
494                 domain = g_strdup (username);
495                 slash = domain + (slash - username);
496                 *slash = '\0';
497                 username = slash + 1;
498         } else
499                 domain = conn->domain;
500
501         conn->response_header = soup_ntlm_response (conn->nonce,
502                                                     username, password,
503                                                     NULL, domain);
504
505         flags = soup_message_get_flags (msg);
506         soup_message_set_flags (msg, flags & ~SOUP_MESSAGE_NEW_CONNECTION);
507         soup_session_requeue_message (priv->session, msg);
508
509 done:
510         if (domain != conn->domain)
511                 g_free (domain);
512         g_free (conn->domain);
513         conn->domain = NULL;
514         g_free (conn->nonce);
515         conn->nonce = NULL;
516         g_object_unref (conn->auth);
517         conn->auth = NULL;
518 }
519
520 static void
521 request_queued (SoupSessionFeature *ntlm, SoupSession *session, SoupMessage *msg)
522 {
523         SoupAuthManagerNTLMPrivate *priv =
524                 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (ntlm);
525
526         if (priv->use_ntlm) {
527                 soup_message_add_status_code_handler (
528                         msg, "got_headers", SOUP_STATUS_UNAUTHORIZED,
529                         G_CALLBACK (ntlm_authorize_pre), ntlm);
530                 soup_message_add_status_code_handler (
531                         msg, "got_body", SOUP_STATUS_UNAUTHORIZED,
532                         G_CALLBACK (ntlm_authorize_post), ntlm);
533         }
534
535         soup_auth_manager_parent_feature_interface->request_queued (ntlm, session, msg);
536 }
537
538 static void
539 request_started (SoupSessionFeature *ntlm, SoupSession *session,
540                  SoupMessage *msg, SoupSocket *socket)
541 {
542         SoupAuthManagerNTLMPrivate *priv =
543                 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (ntlm);
544         SoupNTLMConnection *conn;
545         char *header = NULL;
546
547         if (!priv->use_ntlm)
548                 goto super;
549
550         conn = get_connection (priv, socket);
551         set_connection_for_msg (priv, msg, conn);
552
553         switch (conn->state) {
554         case SOUP_NTLM_NEW:
555 #ifdef USE_NTLM_AUTH
556                 /* Use Samba's 'winbind' daemon to support NTLM single-sign-on,
557                  * by delegating the NTLM challenge/response protocal to a helper
558                  * in ntlm_auth.
559                  * http://devel.squid-cache.org/ntlm/squid_helper_protocol.html
560                  * http://www.samba.org/samba/docs/man/manpages-3/winbindd.8.html
561                  * http://www.samba.org/samba/docs/man/manpages-3/ntlm_auth.1.html
562                  * The preprocessor variable 'USE_NTLM_AUTH' indicates whether
563                  * this feature is enabled. Another one 'NTLM_AUTH' contains absolute
564                  * path of it.
565                  * If NTLM single-sign-on fails, go back to original request handling process.
566                  */
567                 if (sso_ntlm_initiate (conn, priv)) {
568                         header = sso_ntlm_response (conn, "YR\n", conn->state);
569                         if (header) {
570                                 if (g_ascii_strcasecmp (header, "PW") != 0) {
571                                         conn->state = SOUP_NTLM_SENT_SSO_REQUEST;
572                                         break;
573                                 } else {
574                                         g_free (header);
575                                         header = NULL;
576                                         goto ssofailure;
577                                 }
578                         } else {
579                                 g_warning ("NTLM single-sign-on by using %s failed", NTLM_AUTH);
580                                 goto ssofailure;
581                         }
582                 }
583 ssofailure:
584 #endif
585                 header = soup_ntlm_request ();
586                 conn->state = SOUP_NTLM_SENT_REQUEST;
587                 break;
588 #ifdef USE_NTLM_AUTH
589         case SOUP_NTLM_RECEIVED_SSO_CHALLENGE:
590                 header = conn->response_header;
591                 conn->response_header = NULL;
592                 conn->state = SOUP_NTLM_SENT_SSO_RESPONSE;
593                 break;
594         case SOUP_NTLM_SSO_FAILED:
595                 /* Restart request without SSO */
596                 g_warning ("NTLM single-sign-on by using %s failed", NTLM_AUTH);
597                 header = soup_ntlm_request ();
598                 conn->state = SOUP_NTLM_SENT_REQUEST;
599                 break;
600 #endif
601         case SOUP_NTLM_RECEIVED_CHALLENGE:
602                 header = conn->response_header;
603                 conn->response_header = NULL;
604                 conn->state = SOUP_NTLM_SENT_RESPONSE;
605                 break;
606         default:
607                 break;
608         }
609
610         if (header && !soup_message_get_auth (msg)) {
611                 soup_message_headers_replace (msg->request_headers,
612                                               "Authorization", header);
613                 g_free (header);
614         }
615
616 super:
617         soup_auth_manager_parent_feature_interface->request_started (ntlm, session, msg, socket);
618 }
619
620 static void
621 request_unqueued (SoupSessionFeature *ntlm, SoupSession *session,
622                   SoupMessage *msg)
623 {
624         g_signal_handlers_disconnect_by_func (msg, ntlm_authorize_pre, ntlm);
625         g_signal_handlers_disconnect_by_func (msg, ntlm_authorize_post, ntlm);
626
627         soup_auth_manager_parent_feature_interface->request_unqueued (ntlm, session, msg);
628 }
629
630 static gboolean
631 add_feature (SoupSessionFeature *feature, GType type)
632 {
633         SoupAuthManagerNTLMPrivate *priv =
634                 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (feature);
635
636         if (type == SOUP_TYPE_AUTH_NTLM) {
637                 priv->use_ntlm = TRUE;
638                 return TRUE;
639         }
640
641         return soup_auth_manager_parent_feature_interface->add_feature (feature, type);
642 }
643
644 static gboolean
645 remove_feature (SoupSessionFeature *feature, GType type)
646 {
647         SoupAuthManagerNTLMPrivate *priv =
648                 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (feature);
649
650         if (type == SOUP_TYPE_AUTH_NTLM) {
651                 priv->use_ntlm = FALSE;
652                 return TRUE;
653         }
654
655         return soup_auth_manager_parent_feature_interface->remove_feature (feature, type);
656 }
657
658 static gboolean
659 has_feature (SoupSessionFeature *feature, GType type)
660 {
661         SoupAuthManagerNTLMPrivate *priv =
662                 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (feature);
663
664         if (type == SOUP_TYPE_AUTH_NTLM)
665                 return priv->use_ntlm;
666
667         return soup_auth_manager_parent_feature_interface->has_feature (feature, type);
668 }
669
670 /* NTLM code */
671
672 static void md4sum                (const unsigned char *in, 
673                                    int                  nbytes, 
674                                    unsigned char        digest[16]);
675
676 typedef guint32 DES_KS[16][2]; /* Single-key DES key schedule */
677
678 static void deskey                (DES_KS, unsigned char *, int);
679
680 static void des                   (DES_KS, unsigned char *);
681
682 static void setup_schedule        (const guchar *key_56, DES_KS ks);
683
684 static void calc_response         (const guchar        *key, 
685                                    const guchar        *plaintext,
686                                    guchar              *results);
687
688 #define LM_PASSWORD_MAGIC "\x4B\x47\x53\x21\x40\x23\x24\x25" \
689                           "\x4B\x47\x53\x21\x40\x23\x24\x25" \
690                           "\x00\x00\x00\x00\x00"
691
692 static void
693 lanmanager_hash (const char *password, guchar hash[21])
694 {
695         guchar lm_password [15];
696         DES_KS ks;
697         int i;
698
699         for (i = 0; i < 14 && password [i]; i++)
700                 lm_password [i] = toupper ((unsigned char) password [i]);
701
702         for (; i < 15; i++)
703                 lm_password [i] = '\0';
704
705         memcpy (hash, LM_PASSWORD_MAGIC, 21);
706
707         setup_schedule (lm_password, ks);
708         des (ks, hash);
709
710         setup_schedule (lm_password + 7, ks);
711         des (ks, hash + 8);
712 }
713
714 static void
715 nt_hash (const char *password, guchar hash[21])
716 {
717         unsigned char *buf, *p;
718
719         p = buf = g_malloc (strlen (password) * 2);
720
721         while (*password) {
722                 *p++ = *password++;
723                 *p++ = '\0';
724         }
725
726         md4sum (buf, p - buf, hash);
727         memset (hash + 16, 0, 5);
728
729         g_free (buf);
730 }
731
732 typedef struct {
733         guint16 length;
734         guint16 length2;
735         guint16 offset;
736         guchar  zero_pad[2];
737 } NTLMString;
738
739 #define NTLM_CHALLENGE_NONCE_OFFSET         24
740 #define NTLM_CHALLENGE_NONCE_LENGTH          8
741 #define NTLM_CHALLENGE_DOMAIN_STRING_OFFSET 12
742
743 #define NTLM_RESPONSE_HEADER "NTLMSSP\x00\x03\x00\x00\x00"
744 #define NTLM_RESPONSE_FLAGS 0x8201
745
746 typedef struct {
747         guchar     header[12];
748
749         NTLMString lm_resp;
750         NTLMString nt_resp;
751         NTLMString domain;
752         NTLMString user;
753         NTLMString host;
754         NTLMString session_key;
755
756         guint32    flags;
757 } NTLMResponse;
758
759 static void
760 ntlm_set_string (NTLMString *string, int *offset, int len)
761 {
762         string->offset = GUINT16_TO_LE (*offset);
763         string->length = string->length2 = GUINT16_TO_LE (len);
764         *offset += len;
765 }
766
767 static char *
768 soup_ntlm_request (void)
769 {
770         return g_strdup ("NTLM TlRMTVNTUAABAAAABYIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAwAAAA");
771 }
772
773 static gboolean
774 soup_ntlm_parse_challenge (const char *challenge,
775                            char      **nonce,
776                            char      **default_domain)
777 {
778         gsize clen;
779         NTLMString domain;
780         guchar *chall;
781
782         if (strncmp (challenge, "NTLM ", 5) != 0)
783                 return FALSE;
784
785         chall = g_base64_decode (challenge + 5, &clen);
786         if (clen < NTLM_CHALLENGE_DOMAIN_STRING_OFFSET ||
787             clen < NTLM_CHALLENGE_NONCE_OFFSET + NTLM_CHALLENGE_NONCE_LENGTH) {
788                 g_free (chall);
789                 return FALSE;
790         }
791
792         if (default_domain) {
793                 memcpy (&domain, chall + NTLM_CHALLENGE_DOMAIN_STRING_OFFSET, sizeof (domain));
794                 domain.length = GUINT16_FROM_LE (domain.length);
795                 domain.offset = GUINT16_FROM_LE (domain.offset);
796
797                 if (clen < domain.length + domain.offset) {
798                         g_free (chall);
799                         return FALSE;
800                 }
801
802                 *default_domain = g_convert ((char *)chall + domain.offset,
803                                              domain.length, "UTF-8", "UCS-2LE",
804                                              NULL, NULL, NULL);
805         }
806
807         if (nonce) {
808                 *nonce = g_memdup (chall + NTLM_CHALLENGE_NONCE_OFFSET,
809                                    NTLM_CHALLENGE_NONCE_LENGTH);
810         }
811
812         g_free (chall);
813         return TRUE;
814 }
815
816 static char *
817 soup_ntlm_response (const char *nonce, 
818                     const char *user,
819                     const char *password,
820                     const char *host, 
821                     const char *domain)
822 {
823         int offset;
824         gsize hlen, dlen, ulen;
825         guchar hash[21], lm_resp[24], nt_resp[24];
826         char *user_conv, *host_conv, *domain_conv;
827         NTLMResponse resp;
828         char *out, *p;
829         int state, save;
830
831         nt_hash (password, hash);
832         calc_response (hash, (guchar *)nonce, nt_resp);
833         lanmanager_hash (password, hash);
834         calc_response (hash, (guchar *)nonce, lm_resp);
835
836         memset (&resp, 0, sizeof (resp));
837         memcpy (resp.header, NTLM_RESPONSE_HEADER, sizeof (resp.header));
838         resp.flags = GUINT32_TO_LE (NTLM_RESPONSE_FLAGS);
839
840         offset = sizeof (resp);
841
842         if (!host)
843                 host = "UNKNOWN";
844
845         domain_conv = g_convert (domain, -1, "UCS-2LE", "UTF-8", NULL, &dlen, NULL);
846         user_conv = g_convert (user, -1, "UCS-2LE", "UTF-8", NULL, &ulen, NULL);
847         host_conv = g_convert (host, -1, "UCS-2LE", "UTF-8", NULL, &hlen, NULL);
848
849         ntlm_set_string (&resp.domain, &offset, dlen);
850         ntlm_set_string (&resp.user, &offset, ulen);
851         ntlm_set_string (&resp.host, &offset, hlen);
852         ntlm_set_string (&resp.lm_resp, &offset, sizeof (lm_resp));
853         ntlm_set_string (&resp.nt_resp, &offset, sizeof (nt_resp));
854
855         out = g_malloc (((offset + 3) * 4) / 3 + 6);
856         strncpy (out, "NTLM ", 5);
857         p = out + 5;
858
859         state = save = 0;
860
861         p += g_base64_encode_step ((const guchar *) &resp, sizeof (resp), 
862                                    FALSE, p, &state, &save);
863         p += g_base64_encode_step ((const guchar *) domain_conv, dlen,
864                                    FALSE, p, &state, &save);
865         p += g_base64_encode_step ((const guchar *) user_conv, ulen,
866                                    FALSE, p, &state, &save);
867         p += g_base64_encode_step ((const guchar *) host_conv, hlen,
868                                    FALSE, p, &state, &save);
869         p += g_base64_encode_step (lm_resp, sizeof (lm_resp), 
870                                    FALSE, p, &state, &save);
871         p += g_base64_encode_step (nt_resp, sizeof (nt_resp), 
872                                    FALSE, p, &state, &save);
873         p += g_base64_encode_close (FALSE, p, &state, &save);
874         *p = '\0';
875
876         g_free (domain_conv);
877         g_free (user_conv);
878         g_free (host_conv);
879
880         return out;
881 }
882
883 /* DES utils */
884 /* Set up a key schedule based on a 56bit key */
885 static void
886 setup_schedule (const guchar *key_56, DES_KS ks)
887 {
888         guchar key[8];
889         int i, c, bit;
890
891         key[0] = (key_56[0])                                 ;
892         key[1] = (key_56[1] >> 1) | ((key_56[0] << 7) & 0xFF);
893         key[2] = (key_56[2] >> 2) | ((key_56[1] << 6) & 0xFF);
894         key[3] = (key_56[3] >> 3) | ((key_56[2] << 5) & 0xFF);
895         key[4] = (key_56[4] >> 4) | ((key_56[3] << 4) & 0xFF);
896         key[5] = (key_56[5] >> 5) | ((key_56[4] << 3) & 0xFF);
897         key[6] = (key_56[6] >> 6) | ((key_56[5] << 2) & 0xFF);
898         key[7] =                    ((key_56[6] << 1) & 0xFF);
899
900         /* Fix parity */
901         for (i = 0; i < 8; i++) {
902                 for (c = bit = 0; bit < 8; bit++)
903                         if (key[i] & (1 << bit))
904                                 c++;
905                 if (!(c & 1))
906                         key[i] ^= 0x01;
907         }
908
909         deskey (ks, key, 0);
910 }
911
912 static void
913 calc_response (const guchar *key, const guchar *plaintext, guchar *results)
914 {
915         DES_KS ks;
916
917         memcpy (results, plaintext, 8);
918         memcpy (results + 8, plaintext, 8);
919         memcpy (results + 16, plaintext, 8);
920
921         setup_schedule (key, ks);
922         des (ks, results);
923
924         setup_schedule (key + 7, ks);
925         des (ks, results + 8);
926
927         setup_schedule (key + 14, ks);
928         des (ks, results + 16);
929 }
930
931
932 /* 
933  * MD4 encoder. (The one everyone else uses is not GPL-compatible;
934  * this is a reimplementation from spec.) This doesn't need to be
935  * efficient for our purposes, although it would be nice to fix
936  * it to not malloc()...
937  */
938
939 #define F(X,Y,Z) ( ((X)&(Y)) | ((~(X))&(Z)) )
940 #define G(X,Y,Z) ( ((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z)) )
941 #define H(X,Y,Z) ( (X)^(Y)^(Z) )
942 #define ROT(val, n) ( ((val) << (n)) | ((val) >> (32 - (n))) )
943
944 static void
945 md4sum (const unsigned char *in, int nbytes, unsigned char digest[16])
946 {
947         unsigned char *M;
948         guint32 A, B, C, D, AA, BB, CC, DD, X[16];
949         int pbytes, nbits = nbytes * 8, i, j;
950
951         pbytes = (120 - (nbytes % 64)) % 64;
952         M = alloca (nbytes + pbytes + 8);
953         memcpy (M, in, nbytes);
954         memset (M + nbytes, 0, pbytes + 8);
955         M[nbytes] = 0x80;
956         M[nbytes + pbytes] = nbits & 0xFF;
957         M[nbytes + pbytes + 1] = (nbits >> 8) & 0xFF;
958         M[nbytes + pbytes + 2] = (nbits >> 16) & 0xFF;
959         M[nbytes + pbytes + 3] = (nbits >> 24) & 0xFF;
960
961         A = 0x67452301;
962         B = 0xEFCDAB89;
963         C = 0x98BADCFE;
964         D = 0x10325476;
965
966         for (i = 0; i < nbytes + pbytes + 8; i += 64) {
967                 for (j = 0; j < 16; j++) {
968                         X[j] =  (M[i + j*4]) |
969                                 (M[i + j*4 + 1] << 8) |
970                                 (M[i + j*4 + 2] << 16) |
971                                 (M[i + j*4 + 3] << 24);
972                 }
973
974                 AA = A;
975                 BB = B;
976                 CC = C;
977                 DD = D;
978
979                 A = ROT (A + F(B, C, D) + X[0], 3);
980                 D = ROT (D + F(A, B, C) + X[1], 7);
981                 C = ROT (C + F(D, A, B) + X[2], 11);
982                 B = ROT (B + F(C, D, A) + X[3], 19);
983                 A = ROT (A + F(B, C, D) + X[4], 3);
984                 D = ROT (D + F(A, B, C) + X[5], 7);
985                 C = ROT (C + F(D, A, B) + X[6], 11);
986                 B = ROT (B + F(C, D, A) + X[7], 19);
987                 A = ROT (A + F(B, C, D) + X[8], 3);
988                 D = ROT (D + F(A, B, C) + X[9], 7);
989                 C = ROT (C + F(D, A, B) + X[10], 11);
990                 B = ROT (B + F(C, D, A) + X[11], 19);
991                 A = ROT (A + F(B, C, D) + X[12], 3);
992                 D = ROT (D + F(A, B, C) + X[13], 7);
993                 C = ROT (C + F(D, A, B) + X[14], 11);
994                 B = ROT (B + F(C, D, A) + X[15], 19);
995
996                 A = ROT (A + G(B, C, D) + X[0] + 0x5A827999, 3);
997                 D = ROT (D + G(A, B, C) + X[4] + 0x5A827999, 5);
998                 C = ROT (C + G(D, A, B) + X[8] + 0x5A827999, 9);
999                 B = ROT (B + G(C, D, A) + X[12] + 0x5A827999, 13);
1000                 A = ROT (A + G(B, C, D) + X[1] + 0x5A827999, 3);
1001                 D = ROT (D + G(A, B, C) + X[5] + 0x5A827999, 5);
1002                 C = ROT (C + G(D, A, B) + X[9] + 0x5A827999, 9);
1003                 B = ROT (B + G(C, D, A) + X[13] + 0x5A827999, 13);
1004                 A = ROT (A + G(B, C, D) + X[2] + 0x5A827999, 3);
1005                 D = ROT (D + G(A, B, C) + X[6] + 0x5A827999, 5);
1006                 C = ROT (C + G(D, A, B) + X[10] + 0x5A827999, 9);
1007                 B = ROT (B + G(C, D, A) + X[14] + 0x5A827999, 13);
1008                 A = ROT (A + G(B, C, D) + X[3] + 0x5A827999, 3);
1009                 D = ROT (D + G(A, B, C) + X[7] + 0x5A827999, 5);
1010                 C = ROT (C + G(D, A, B) + X[11] + 0x5A827999, 9);
1011                 B = ROT (B + G(C, D, A) + X[15] + 0x5A827999, 13);
1012
1013                 A = ROT (A + H(B, C, D) + X[0] + 0x6ED9EBA1, 3);
1014                 D = ROT (D + H(A, B, C) + X[8] + 0x6ED9EBA1, 9);
1015                 C = ROT (C + H(D, A, B) + X[4] + 0x6ED9EBA1, 11);
1016                 B = ROT (B + H(C, D, A) + X[12] + 0x6ED9EBA1, 15);
1017                 A = ROT (A + H(B, C, D) + X[2] + 0x6ED9EBA1, 3);
1018                 D = ROT (D + H(A, B, C) + X[10] + 0x6ED9EBA1, 9);
1019                 C = ROT (C + H(D, A, B) + X[6] + 0x6ED9EBA1, 11);
1020                 B = ROT (B + H(C, D, A) + X[14] + 0x6ED9EBA1, 15);
1021                 A = ROT (A + H(B, C, D) + X[1] + 0x6ED9EBA1, 3);
1022                 D = ROT (D + H(A, B, C) + X[9] + 0x6ED9EBA1, 9);
1023                 C = ROT (C + H(D, A, B) + X[5] + 0x6ED9EBA1, 11);
1024                 B = ROT (B + H(C, D, A) + X[13] + 0x6ED9EBA1, 15);
1025                 A = ROT (A + H(B, C, D) + X[3] + 0x6ED9EBA1, 3);
1026                 D = ROT (D + H(A, B, C) + X[11] + 0x6ED9EBA1, 9);
1027                 C = ROT (C + H(D, A, B) + X[7] + 0x6ED9EBA1, 11);
1028                 B = ROT (B + H(C, D, A) + X[15] + 0x6ED9EBA1, 15);
1029
1030                 A += AA;
1031                 B += BB;
1032                 C += CC;
1033                 D += DD;
1034         }
1035
1036         digest[0]  =  A        & 0xFF;
1037         digest[1]  = (A >>  8) & 0xFF;
1038         digest[2]  = (A >> 16) & 0xFF;
1039         digest[3]  = (A >> 24) & 0xFF;
1040         digest[4]  =  B        & 0xFF;
1041         digest[5]  = (B >>  8) & 0xFF;
1042         digest[6]  = (B >> 16) & 0xFF;
1043         digest[7]  = (B >> 24) & 0xFF;
1044         digest[8]  =  C        & 0xFF;
1045         digest[9]  = (C >>  8) & 0xFF;
1046         digest[10] = (C >> 16) & 0xFF;
1047         digest[11] = (C >> 24) & 0xFF;
1048         digest[12] =  D        & 0xFF;
1049         digest[13] = (D >>  8) & 0xFF;
1050         digest[14] = (D >> 16) & 0xFF;
1051         digest[15] = (D >> 24) & 0xFF;
1052 }
1053
1054
1055 /* Public domain DES implementation from Phil Karn */
1056 static const guint32 Spbox[8][64] = {
1057         { 0x01010400,0x00000000,0x00010000,0x01010404,
1058           0x01010004,0x00010404,0x00000004,0x00010000,
1059           0x00000400,0x01010400,0x01010404,0x00000400,
1060           0x01000404,0x01010004,0x01000000,0x00000004,
1061           0x00000404,0x01000400,0x01000400,0x00010400,
1062           0x00010400,0x01010000,0x01010000,0x01000404,
1063           0x00010004,0x01000004,0x01000004,0x00010004,
1064           0x00000000,0x00000404,0x00010404,0x01000000,
1065           0x00010000,0x01010404,0x00000004,0x01010000,
1066           0x01010400,0x01000000,0x01000000,0x00000400,
1067           0x01010004,0x00010000,0x00010400,0x01000004,
1068           0x00000400,0x00000004,0x01000404,0x00010404,
1069           0x01010404,0x00010004,0x01010000,0x01000404,
1070           0x01000004,0x00000404,0x00010404,0x01010400,
1071           0x00000404,0x01000400,0x01000400,0x00000000,
1072           0x00010004,0x00010400,0x00000000,0x01010004 },
1073         { 0x80108020,0x80008000,0x00008000,0x00108020,
1074           0x00100000,0x00000020,0x80100020,0x80008020,
1075           0x80000020,0x80108020,0x80108000,0x80000000,
1076           0x80008000,0x00100000,0x00000020,0x80100020,
1077           0x00108000,0x00100020,0x80008020,0x00000000,
1078           0x80000000,0x00008000,0x00108020,0x80100000,
1079           0x00100020,0x80000020,0x00000000,0x00108000,
1080           0x00008020,0x80108000,0x80100000,0x00008020,
1081           0x00000000,0x00108020,0x80100020,0x00100000,
1082           0x80008020,0x80100000,0x80108000,0x00008000,
1083           0x80100000,0x80008000,0x00000020,0x80108020,
1084           0x00108020,0x00000020,0x00008000,0x80000000,
1085           0x00008020,0x80108000,0x00100000,0x80000020,
1086           0x00100020,0x80008020,0x80000020,0x00100020,
1087           0x00108000,0x00000000,0x80008000,0x00008020,
1088           0x80000000,0x80100020,0x80108020,0x00108000 },
1089         { 0x00000208,0x08020200,0x00000000,0x08020008,
1090           0x08000200,0x00000000,0x00020208,0x08000200,
1091           0x00020008,0x08000008,0x08000008,0x00020000,
1092           0x08020208,0x00020008,0x08020000,0x00000208,
1093           0x08000000,0x00000008,0x08020200,0x00000200,
1094           0x00020200,0x08020000,0x08020008,0x00020208,
1095           0x08000208,0x00020200,0x00020000,0x08000208,
1096           0x00000008,0x08020208,0x00000200,0x08000000,
1097           0x08020200,0x08000000,0x00020008,0x00000208,
1098           0x00020000,0x08020200,0x08000200,0x00000000,
1099           0x00000200,0x00020008,0x08020208,0x08000200,
1100           0x08000008,0x00000200,0x00000000,0x08020008,
1101           0x08000208,0x00020000,0x08000000,0x08020208,
1102           0x00000008,0x00020208,0x00020200,0x08000008,
1103           0x08020000,0x08000208,0x00000208,0x08020000,
1104           0x00020208,0x00000008,0x08020008,0x00020200 },
1105         { 0x00802001,0x00002081,0x00002081,0x00000080,
1106           0x00802080,0x00800081,0x00800001,0x00002001,
1107           0x00000000,0x00802000,0x00802000,0x00802081,
1108           0x00000081,0x00000000,0x00800080,0x00800001,
1109           0x00000001,0x00002000,0x00800000,0x00802001,
1110           0x00000080,0x00800000,0x00002001,0x00002080,
1111           0x00800081,0x00000001,0x00002080,0x00800080,
1112           0x00002000,0x00802080,0x00802081,0x00000081,
1113           0x00800080,0x00800001,0x00802000,0x00802081,
1114           0x00000081,0x00000000,0x00000000,0x00802000,
1115           0x00002080,0x00800080,0x00800081,0x00000001,
1116           0x00802001,0x00002081,0x00002081,0x00000080,
1117           0x00802081,0x00000081,0x00000001,0x00002000,
1118           0x00800001,0x00002001,0x00802080,0x00800081,
1119           0x00002001,0x00002080,0x00800000,0x00802001,
1120           0x00000080,0x00800000,0x00002000,0x00802080 },
1121         { 0x00000100,0x02080100,0x02080000,0x42000100,
1122           0x00080000,0x00000100,0x40000000,0x02080000,
1123           0x40080100,0x00080000,0x02000100,0x40080100,
1124           0x42000100,0x42080000,0x00080100,0x40000000,
1125           0x02000000,0x40080000,0x40080000,0x00000000,
1126           0x40000100,0x42080100,0x42080100,0x02000100,
1127           0x42080000,0x40000100,0x00000000,0x42000000,
1128           0x02080100,0x02000000,0x42000000,0x00080100,
1129           0x00080000,0x42000100,0x00000100,0x02000000,
1130           0x40000000,0x02080000,0x42000100,0x40080100,
1131           0x02000100,0x40000000,0x42080000,0x02080100,
1132           0x40080100,0x00000100,0x02000000,0x42080000,
1133           0x42080100,0x00080100,0x42000000,0x42080100,
1134           0x02080000,0x00000000,0x40080000,0x42000000,
1135           0x00080100,0x02000100,0x40000100,0x00080000,
1136           0x00000000,0x40080000,0x02080100,0x40000100 },
1137         { 0x20000010,0x20400000,0x00004000,0x20404010,
1138           0x20400000,0x00000010,0x20404010,0x00400000,
1139           0x20004000,0x00404010,0x00400000,0x20000010,
1140           0x00400010,0x20004000,0x20000000,0x00004010,
1141           0x00000000,0x00400010,0x20004010,0x00004000,
1142           0x00404000,0x20004010,0x00000010,0x20400010,
1143           0x20400010,0x00000000,0x00404010,0x20404000,
1144           0x00004010,0x00404000,0x20404000,0x20000000,
1145           0x20004000,0x00000010,0x20400010,0x00404000,
1146           0x20404010,0x00400000,0x00004010,0x20000010,
1147           0x00400000,0x20004000,0x20000000,0x00004010,
1148           0x20000010,0x20404010,0x00404000,0x20400000,
1149           0x00404010,0x20404000,0x00000000,0x20400010,
1150           0x00000010,0x00004000,0x20400000,0x00404010,
1151           0x00004000,0x00400010,0x20004010,0x00000000,
1152           0x20404000,0x20000000,0x00400010,0x20004010 },
1153         { 0x00200000,0x04200002,0x04000802,0x00000000,
1154           0x00000800,0x04000802,0x00200802,0x04200800,
1155           0x04200802,0x00200000,0x00000000,0x04000002,
1156           0x00000002,0x04000000,0x04200002,0x00000802,
1157           0x04000800,0x00200802,0x00200002,0x04000800,
1158           0x04000002,0x04200000,0x04200800,0x00200002,
1159           0x04200000,0x00000800,0x00000802,0x04200802,
1160           0x00200800,0x00000002,0x04000000,0x00200800,
1161           0x04000000,0x00200800,0x00200000,0x04000802,
1162           0x04000802,0x04200002,0x04200002,0x00000002,
1163           0x00200002,0x04000000,0x04000800,0x00200000,
1164           0x04200800,0x00000802,0x00200802,0x04200800,
1165           0x00000802,0x04000002,0x04200802,0x04200000,
1166           0x00200800,0x00000000,0x00000002,0x04200802,
1167           0x00000000,0x00200802,0x04200000,0x00000800,
1168           0x04000002,0x04000800,0x00000800,0x00200002 },
1169         { 0x10001040,0x00001000,0x00040000,0x10041040,
1170           0x10000000,0x10001040,0x00000040,0x10000000,
1171           0x00040040,0x10040000,0x10041040,0x00041000,
1172           0x10041000,0x00041040,0x00001000,0x00000040,
1173           0x10040000,0x10000040,0x10001000,0x00001040,
1174           0x00041000,0x00040040,0x10040040,0x10041000,
1175           0x00001040,0x00000000,0x00000000,0x10040040,
1176           0x10000040,0x10001000,0x00041040,0x00040000,
1177           0x00041040,0x00040000,0x10041000,0x00001000,
1178           0x00000040,0x10040040,0x00001000,0x00041040,
1179           0x10001000,0x00000040,0x10000040,0x10040000,
1180           0x10040040,0x10000000,0x00040000,0x10001040,
1181           0x00000000,0x10041040,0x00040040,0x10000040,
1182           0x10040000,0x10001000,0x10001040,0x00000000,
1183           0x10041040,0x00041000,0x00041000,0x00001040,
1184           0x00001040,0x00040040,0x10000000,0x10041000 }
1185 };
1186
1187 #undef F
1188 #define F(l,r,key){\
1189         work = ((r >> 4) | (r << 28)) ^ key[0];\
1190         l ^= Spbox[6][work & 0x3f];\
1191         l ^= Spbox[4][(work >> 8) & 0x3f];\
1192         l ^= Spbox[2][(work >> 16) & 0x3f];\
1193         l ^= Spbox[0][(work >> 24) & 0x3f];\
1194         work = r ^ key[1];\
1195         l ^= Spbox[7][work & 0x3f];\
1196         l ^= Spbox[5][(work >> 8) & 0x3f];\
1197         l ^= Spbox[3][(work >> 16) & 0x3f];\
1198         l ^= Spbox[1][(work >> 24) & 0x3f];\
1199 }
1200 /* Encrypt or decrypt a block of data in ECB mode */
1201 static void
1202 des (guint32 ks[16][2], unsigned char block[8])
1203 {
1204         guint32 left,right,work;
1205         
1206         /* Read input block and place in left/right in big-endian order */
1207         left = ((guint32)block[0] << 24)
1208          | ((guint32)block[1] << 16)
1209          | ((guint32)block[2] << 8)
1210          | (guint32)block[3];
1211         right = ((guint32)block[4] << 24)
1212          | ((guint32)block[5] << 16)
1213          | ((guint32)block[6] << 8)
1214          | (guint32)block[7];
1215
1216         /* Hoey's clever initial permutation algorithm, from Outerbridge
1217          * (see Schneier p 478) 
1218          *
1219          * The convention here is the same as Outerbridge: rotate each
1220          * register left by 1 bit, i.e., so that "left" contains permuted
1221          * input bits 2, 3, 4, ... 1 and "right" contains 33, 34, 35, ... 32    
1222          * (using origin-1 numbering as in the FIPS). This allows us to avoid
1223          * one of the two rotates that would otherwise be required in each of
1224          * the 16 rounds.
1225          */
1226         work = ((left >> 4) ^ right) & 0x0f0f0f0f;
1227         right ^= work;
1228         left ^= work << 4;
1229         work = ((left >> 16) ^ right) & 0xffff;
1230         right ^= work;
1231         left ^= work << 16;
1232         work = ((right >> 2) ^ left) & 0x33333333;
1233         left ^= work;
1234         right ^= (work << 2);
1235         work = ((right >> 8) ^ left) & 0xff00ff;
1236         left ^= work;
1237         right ^= (work << 8);
1238         right = (right << 1) | (right >> 31);
1239         work = (left ^ right) & 0xaaaaaaaa;
1240         left ^= work;
1241         right ^= work;
1242         left = (left << 1) | (left >> 31);
1243
1244         /* Now do the 16 rounds */
1245         F(left,right,ks[0]);
1246         F(right,left,ks[1]);
1247         F(left,right,ks[2]);
1248         F(right,left,ks[3]);
1249         F(left,right,ks[4]);
1250         F(right,left,ks[5]);
1251         F(left,right,ks[6]);
1252         F(right,left,ks[7]);
1253         F(left,right,ks[8]);
1254         F(right,left,ks[9]);
1255         F(left,right,ks[10]);
1256         F(right,left,ks[11]);
1257         F(left,right,ks[12]);
1258         F(right,left,ks[13]);
1259         F(left,right,ks[14]);
1260         F(right,left,ks[15]);
1261
1262         /* Inverse permutation, also from Hoey via Outerbridge and Schneier */
1263         right = (right << 31) | (right >> 1);
1264         work = (left ^ right) & 0xaaaaaaaa;
1265         left ^= work;
1266         right ^= work;
1267         left = (left >> 1) | (left  << 31);
1268         work = ((left >> 8) ^ right) & 0xff00ff;
1269         right ^= work;
1270         left ^= work << 8;
1271         work = ((left >> 2) ^ right) & 0x33333333;
1272         right ^= work;
1273         left ^= work << 2;
1274         work = ((right >> 16) ^ left) & 0xffff;
1275         left ^= work;
1276         right ^= work << 16;
1277         work = ((right >> 4) ^ left) & 0x0f0f0f0f;
1278         left ^= work;
1279         right ^= work << 4;
1280
1281         /* Put the block back into the user's buffer with final swap */
1282         block[0] = right >> 24;
1283         block[1] = right >> 16;
1284         block[2] = right >> 8;
1285         block[3] = right;
1286         block[4] = left >> 24;
1287         block[5] = left >> 16;
1288         block[6] = left >> 8;
1289         block[7] = left;
1290 }
1291
1292 /* Key schedule-related tables from FIPS-46 */
1293
1294 /* permuted choice table (key) */
1295 static const unsigned char pc1[] = {
1296         57, 49, 41, 33, 25, 17,  9,
1297          1, 58, 50, 42, 34, 26, 18,
1298         10,  2, 59, 51, 43, 35, 27,
1299         19, 11,  3, 60, 52, 44, 36,
1300
1301         63, 55, 47, 39, 31, 23, 15,
1302          7, 62, 54, 46, 38, 30, 22,
1303         14,  6, 61, 53, 45, 37, 29,
1304         21, 13,  5, 28, 20, 12,  4
1305 };
1306
1307 /* number left rotations of pc1 */
1308 static const unsigned char totrot[] = {
1309         1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28
1310 };
1311
1312 /* permuted choice key (table) */
1313 static const unsigned char pc2[] = {
1314         14, 17, 11, 24,  1,  5,
1315          3, 28, 15,  6, 21, 10,
1316         23, 19, 12,  4, 26,  8,
1317         16,  7, 27, 20, 13,  2,
1318         41, 52, 31, 37, 47, 55,
1319         30, 40, 51, 45, 33, 48,
1320         44, 49, 39, 56, 34, 53,
1321         46, 42, 50, 36, 29, 32
1322 };
1323
1324 /* End of DES-defined tables */
1325
1326
1327 /* bit 0 is left-most in byte */
1328 static const int bytebit[] = {
1329         0200,0100,040,020,010,04,02,01
1330 };
1331
1332
1333 /* Generate key schedule for encryption or decryption
1334  * depending on the value of "decrypt"
1335  */
1336 static void
1337 deskey (DES_KS k, unsigned char *key, int decrypt)
1338 {
1339         unsigned char pc1m[56];         /* place to modify pc1 into */
1340         unsigned char pcr[56];          /* place to rotate pc1 into */
1341         register int i,j,l;
1342         int m;
1343         unsigned char ks[8];
1344
1345         for (j=0; j<56; j++) {          /* convert pc1 to bits of key */
1346                 l=pc1[j]-1;             /* integer bit location  */
1347                 m = l & 07;             /* find bit              */
1348                 pc1m[j]=(key[l>>3] &    /* find which key byte l is in */
1349                         bytebit[m])     /* and which bit of that byte */
1350                         ? 1 : 0;        /* and store 1-bit result */
1351         }
1352         for (i=0; i<16; i++) {          /* key chunk for each iteration */
1353                 memset(ks,0,sizeof(ks));        /* Clear key schedule */
1354                 for (j=0; j<56; j++)    /* rotate pc1 the right amount */
1355                         pcr[j] = pc1m[(l=j+totrot[decrypt? 15-i : i])<(j<28? 28 : 56) ? l: l-28];
1356                         /* rotate left and right halves independently */
1357                 for (j=0; j<48; j++){   /* select bits individually */
1358                         /* check bit that goes to ks[j] */
1359                         if (pcr[pc2[j]-1]){
1360                                 /* mask it in if it's there */
1361                                 l= j % 6;
1362                                 ks[j/6] |= bytebit[l] >> 2;
1363                         }
1364                 }
1365                 /* Now convert to packed odd/even interleaved form */
1366                 k[i][0] = ((guint32)ks[0] << 24)
1367                  | ((guint32)ks[2] << 16)
1368                  | ((guint32)ks[4] << 8)
1369                  | ((guint32)ks[6]);
1370                 k[i][1] = ((guint32)ks[1] << 24)
1371                  | ((guint32)ks[3] << 16)
1372                  | ((guint32)ks[5] << 8)
1373                  | ((guint32)ks[7]);
1374         }
1375 }