source: roaraudio/libroar/auth.c @ 4998:b404387a2080

Last change on this file since 4998:b404387a2080 was 4790:c1073581d7c2, checked in by phi, 13 years ago

added support for long (> sizeof(mes.data)-4) cookies, fixed memory use-after-free bug in roard

File size: 12.1 KB
RevLine 
[0]1//auth.c:
2
[690]3/*
[4708]4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008-2011
[690]5 *
6 *  This file is part of libroar a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  libroar 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
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
[3517]21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
[690]23 *
24 *  NOTE for everyone want's to change something and send patches:
25 *  read README and HACKING! There a addition information on
26 *  the license of this document you need to read before you send
27 *  any patches.
28 *
29 *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
30 *  or libpulse*:
31 *  The libs libroaresd, libroararts and libroarpulse link this lib
[3740]32 *  and are therefore GPL. Because of this it may be illegal to use
[690]33 *  them with any software that uses libesd, libartsc or libpulse*.
34 */
35
[0]36#include "libroar.h"
37
[3220]38/* How auth works:
39 * 0) set stage to zero
40 * 1) get server address and local node name (from uname())
41 * 2) look up authfile/authdb/authservice for the server+local address + stage.
42 *    if no data was found send NONE-Auth.
43 * 3) send data to server
44 * 4) read answer from server
45 * 5) if stage of server response is non-zero increment stage to server stage+1
46 *    and repeat from step 2)
[3740]47 * 6) check if we got an OK or an ERROR, return correct value
[3220]48 */
49
50/* The protocol:
51 * Auth request:
52 * Byte 0: auth type
53 * Byte 1: stage
54 * Byte 2: reserved (must be zero)
55 * Byte 3: reserved (must be zero)
56 * Byte 4-end: auth type depending data.
57 *
58 * If no data is to be send bytes 2 and 3 can be omitted.
59 * If no data is to be send and stage is zero bytes 1, 2 and 3 can be omitted.
60 *
61 * Auth response:
62 * The same as the auth request.
[3227]63 * if the server sends an zero size message back it means the server accepted our connection
64 * and no additional stage is needed.
[3220]65 * if the message type is OK the server accepted our auth.
[3740]66 * if the message type is ERROR the server rejected us. we may try other auth methods.
[3220]67 * if the server accepted our data and the stage is non-zero we need to continue with the next
68 * stage of the auth.
69 * if the server rejected us the auth type value of the response is a suggested next auth type
70 * we should try if possible. This may help the client to find a working auth type.
71 */
72
73/* The protocol by auth type:
74 *
75 * --- NONE:
76 * No data is send, the server accepts the connect or rejects it depending on some
77 * magic within the server. we do not care about this.
78 * The data block is not used.
79 *
80 * --- COOKIE:
81 * We send cookies for all stages the server ask us to provide a cookie.
[3740]82 * if a cookie is wrong the server rejects us or asks us for another.
[3220]83 * The cookie is send as binary data in the data block.
84 *
85 * --- TRUST:
[3740]86 * We ask the server to auth us based on our UID/GID/PID.
87 * The server may reject this because we are not allowed or because it is not
[3220]88 * supported by the transport.
89 * If we get rejected we may try to continue with IDENT then RHOST before we use NONE.
90 * The data block is not used.
91 *
92 * --- PASSWORD:
[3740]93 * This is technically the same as COOKIE just that the cookie is limited to
[3220]94 * printable ASCII chars and that the user should be asked to provide the password.
95 * This may be done via a GUI popup window.
96 *
97 * --- SYSUSER:
98 * We provide a Username + Password for a system user.
99 * The data block contains of two main parts:
100 * The first part is a one byte long subtype.
101 * The value must be 0x01 for username+password.
[3740]102 * future versions may define other types.
103 * the second part is the actual data block.
[3220]104 * for username+password it is splited into two fields, both terminated with \0.
105 * the first is the username the last one the password as clear text.
106 * Example: char data[] = "\001MyUser\0MyPassword\0";
107 *
108 * --- OPENPGP_SIGN:
109 *
110 * --- OPENPGP_ENCRYPT:
111 *
112 * --- OPENPGP_AUTH:
113 *
114 * --- KERBEROS:
115 * We use Kerberos to auth.
116 *
117 * --- RHOST:
118 * The server is asked to auth us based on our source address.
119 * The data block is not used.
120 *
121 * --- XAUTH:
122 * We send an X11 Cookie.
123 *
124 * --- IDENT:
125 * The server is asked to auth us based on our source address using the IDENT protocol.
126 * The data block is not used.
127 *
128 */
129
[3227]130static int roar_auth_ask_server (struct roar_connection * con, struct roar_auth_message * authmes) {
[4745]131 struct roar_error_frame error_frame;
132 struct roar_message     mes;
133 char                  * header = mes.data;
134 int                     ret;
[4790]135 char                  * data = NULL;
[0]136
[131]137 memset(&mes, 0, sizeof(struct roar_message)); // make valgrind happy!
138
[0]139 mes.cmd     = ROAR_CMD_AUTH;
[4788]140 mes.datalen = 4 + authmes->len;
141
[4790]142 if ( mes.datalen > sizeof(mes.data) ) {
143  data = malloc(mes.datalen);
144  if ( data == NULL )
145   return -1;
146
147  header   = data;
148 }
[3227]149
150 header[0] = authmes->type;
151 header[1] = authmes->stage;
152 header[2] = authmes->reserved.c[0];
153 header[3] = authmes->reserved.c[1];
154
[4788]155 if ( authmes->len ) {
[4790]156  if ( data == NULL ) {
157   memcpy(mes.data + 4, authmes->data, authmes->len);
158  } else {
159   memcpy(data + 4, authmes->data, authmes->len);
160  }
[4788]161 }
162
[4790]163 if ( (ret = roar_req(con, &mes, &data)) == -1 ) {
[4745]164  authmes->type = -1;
[3227]165  return -1;
[4745]166 }
[3227]167
[4790]168 if ( data != NULL ) {
169  header = data;
170 } else {
171  header = mes.data;
172 }
173
[4745]174 if ( mes.cmd != ROAR_CMD_OK ) {
[4790]175  if ( data != NULL ) {
176   // we currently do not support long error frames.
177   free(data);
178   return -1;
179  }
180
[4745]181  ret = -1;
182  if ( roar_err_parsemsg(&mes, &error_frame) == -1 ) {
183   authmes->type = -1;
184   return -1;
185  }
186
187  header = error_frame.data;
188  mes.datalen = error_frame.datalen;
189 }
[4473]190
[3227]191 if ( mes.datalen < 4 ) {
192  memset(header+mes.datalen, 0, 4-mes.datalen);
[4745]193  authmes->type          = -1;
194 } else {
195  authmes->type          = header[0];
[3227]196 }
197
198 authmes->stage         = header[1];
199 authmes->reserved.c[0] = header[2];
200 authmes->reserved.c[1] = header[3];
201
[4790]202 if ( data != NULL )
203  free(data);
204
[4745]205 return ret;
[3227]206}
[0]207
[3227]208static void roar_auth_mes_init(struct roar_auth_message * authmes, int type) {
209 memset(authmes, 0, sizeof(struct roar_auth_message));
210
211 authmes->type  = type;
212 authmes->stage = 0;
213 authmes->data  = NULL;
214 authmes->len   = 0;
215}
216
[4475]217
[4745]218static int try_password (struct roar_connection * con, int * next) {
[4475]219 struct roar_message mes;
220 struct roar_auth_message authmes;
221 char * pw;
222
[4745]223 // TODO: add support for *next.
224
[4475]225 roar_auth_mes_init(&authmes, ROAR_AUTH_T_PASSWORD);
226
227 if ( roar_passwd_simple_ask_pw(&pw, "Password for RoarAudio Server?", NULL) == -1 ) {
228  return -1;
229 }
230
231 authmes.len = strlen(pw);
232
233 if ( roar_auth_init_mes(&mes, &authmes) == -1 ) {
234  roar_mm_free(pw);
235  return -1;
236 }
237
238 // do not use strcpy() because that would copy \0, too.
239 memcpy(authmes.data, pw, authmes.len);
240
241 roar_mm_free(pw);
242
243 if ( roar_req(con, &mes, NULL) == -1 )
244  return -1;
245
246 if ( mes.cmd != ROAR_CMD_OK )
247  return -1;
248
249 if ( roar_auth_from_mes(&authmes, &mes, NULL) == -1 )
250  return -1;
251
252 if ( authmes.stage == 0 )
253  return 0;
254
255 return -1;
256}
257
[4788]258static int try_cookie (struct roar_connection * con, int * next) {
259 struct roar_libroar_config * config = roar_libroar_get_config();
260 struct roar_auth_message authmes;
261 struct roar_authfile * authfile;
262 struct roar_authfile_key * key;
263 int idx;
264 int done = 0;
265
266 roar_auth_mes_init(&authmes, ROAR_AUTH_T_COOKIE);
267
268 if ( (authfile = roar_authfile_open(ROAR_AUTHFILE_TYPE_AUTO, config->authfile, 0, ROAR_AUTHFILE_VERSION_AUTO)) == NULL )
269  return -1;
270
271 for (idx = 0; !done; idx++) {
272  if ( (key = roar_authfile_lookup_key(authfile, ROAR_AUTH_T_COOKIE, idx, NULL)) == NULL )
273   break;
274
275  authmes.data = key->data;
276  authmes.len  = key->len;
277
278  if ( roar_auth_ask_server(con, &authmes) != -1 )
279   done = 1;
280
281  roar_authfile_key_unref(key);
282 }
283
284 roar_authfile_close(authfile);
285
286 return done ? 0 : -1;
287}
288
[3228]289#define _EOL ROAR_AUTH_T_AUTO
[3227]290int roar_auth   (struct roar_connection * con) {
291 struct roar_auth_message authmes;
292 int ret;
[3228]293 int i;
[4745]294 int cur, next;
295 int done;
[3228]296 int ltt[] = {
297              ROAR_AUTH_T_TRUST,
298              ROAR_AUTH_T_IDENT,
299              ROAR_AUTH_T_RHOST,
[4486]300//              ROAR_AUTH_T_PASSWORD,
[4788]301              ROAR_AUTH_T_COOKIE,
[3228]302              ROAR_AUTH_T_NONE,
303              _EOL
304             };
[3227]305
[3228]306 for (i = 0; ltt[i] != _EOL; i++) {
[4745]307  next = ltt[i];
308  while (next != -1) {
309   done = 1;
310
311   cur  = next;
312   next = -1;
313
314   switch (cur) {
[4788]315    case ROAR_AUTH_T_PASSWORD:
[4745]316      if ( (ret = try_password(con, &next)) == -1 )
317       done = 0;
318      break;
[4788]319    case ROAR_AUTH_T_TRUST:
320    case ROAR_AUTH_T_IDENT:
321    case ROAR_AUTH_T_RHOST:
322    case ROAR_AUTH_T_NONE:
[4745]323      roar_auth_mes_init(&authmes, ltt[i]);
324      if ( (ret = roar_auth_ask_server(con, &authmes)) == -1 )
325       done = 0;
326
327      next = authmes.type;
[4475]328     break;
[4788]329    case ROAR_AUTH_T_COOKIE:
330      if ( (ret = try_cookie(con, &next)) == -1 )
331       done = 0;
332      break;
333     break;
[4745]334    default: /* Bad error! */
335      return -1;
336     break;
337   }
338
339   if ( authmes.stage != 0 )
340    done = 0;
341
342   if ( done )
343    return 0;
[4475]344  }
[3228]345 }
346
347 return -1;
[0]348}
349
[4470]350
351int roar_auth_from_mes(struct roar_auth_message * ames, struct roar_message * mes, void * data) {
352 void * ibuf;
353 char header[4] = {0, 0, 0, 0};
354
355 if ( ames == NULL || mes == NULL )
356  return -1;
357
[4471]358 if ( data != NULL ) {
[4470]359  ibuf = data;
360 } else {
361  ibuf = mes->data;
362 }
363
364 memset(ames, 0, sizeof(struct roar_auth_message));
365
366 memcpy(header, ibuf, mes->datalen < 4 ? mes->datalen : 4);
367
368 ames->type          = header[0];
369 ames->stage         = header[1];
370 ames->reserved.c[0] = header[2];
371 ames->reserved.c[1] = header[3];
372
373 if ( mes->datalen > 4 ) {
374  ames->data = ibuf + 4;
375  ames->len  = mes->datalen - 4;
376 } else {
377  ames->data = NULL;
378  ames->len  = 0;
379 }
380
381 return 0;
382}
383
384int roar_auth_to_mes(struct roar_message * mes, void ** data, struct roar_auth_message * ames) {
385 char * obuf;
386
387 if ( mes == NULL || ames == NULL )
388  return -1;
389
390 if ( data != NULL )
391  *data = NULL;
392
393 memset(mes, 0, sizeof(struct roar_message));
394
[4475]395 mes->cmd = ROAR_CMD_AUTH;
396
[4470]397 if ( (ames->len + 4) > sizeof(mes->data) ) {
398  *data = malloc(ames->len + 4);
399  if ( *data == NULL )
400   return -1;
401  obuf = *data;
402 } else {
403  obuf = mes->data;
404 }
405
406 obuf[0] = ames->type;
407 obuf[1] = ames->stage;
408 obuf[2] = ames->reserved.c[0];
409 obuf[3] = ames->reserved.c[1];
410
411 memcpy(obuf + 8, ames->data, ames->len);
412
413 mes->datalen = ames->len + 4;
414
415 return 0;
416}
417
418int roar_auth_init_mes(struct roar_message * mes, struct roar_auth_message * ames) {
419 if ( mes == NULL || ames == NULL )
420  return -1;
421
422 if ( (ames->len + 4) > sizeof(mes->data) )
423  return -1;
424
425 memset(mes, 0, sizeof(struct roar_message));
426
[4475]427 mes->cmd = ROAR_CMD_AUTH;
428
[4470]429 mes->data[0] = ames->type;
430 mes->data[1] = ames->stage;
431 mes->data[2] = ames->reserved.c[0];
432 mes->data[3] = ames->reserved.c[1];
433
434 ames->data = &(mes->data[4]);
435
436 mes->datalen = ames->len + 4;
437
438 return 0;
439}
440
441
442
[3225]443// String functions:
444static struct {
445 int    type;
[4296]446 const char * name;
[3225]447} _g_authts[] = {
448// grep ^'#define ROAR_AUTH_T_' auth.h | while read d t d; do n=$(cut -d_ -f4 <<<$t | tr A-Z a-z); printf ' {%-28s %-10s},\n' $t, \"$n\"; done
449 {ROAR_AUTH_T_NONE,            "none"    },
450 {ROAR_AUTH_T_COOKIE,          "cookie"  },
451 {ROAR_AUTH_T_TRUST,           "trust"   },
452 {ROAR_AUTH_T_PASSWORD,        "password"},
453 {ROAR_AUTH_T_SYSUSER,         "sysuser" },
454 {ROAR_AUTH_T_OPENPGP_SIGN,    "openpgp" },
455 {ROAR_AUTH_T_OPENPGP_ENCRYPT, "openpgp" },
456 {ROAR_AUTH_T_OPENPGP_AUTH,    "openpgp" },
457 {ROAR_AUTH_T_KERBEROS,        "kerberos"},
458 {ROAR_AUTH_T_RHOST,           "rhost"   },
459 {ROAR_AUTH_T_XAUTH,           "xauth"   },
460 {ROAR_AUTH_T_IDENT,           "ident"   },
461 {-1, NULL}
462};
463
[4296]464int    roar_str2autht(const char * str) {
[3225]465 int i;
466
467 for (i = 0; _g_authts[i].name != NULL; i++)
468  if ( !strcasecmp(_g_authts[i].name, str) )
469   return _g_authts[i].type;
470
471 return -1;
472}
473
[4296]474const char * roar_autht2str(const int auth) {
[3225]475 int i;
476
477 for (i = 0; _g_authts[i].name != NULL; i++)
478  if ( _g_authts[i].type == auth )
479   return _g_authts[i].name;
480
481 return "(UNKNOWN)";
482}
483
[0]484//ll
Note: See TracBrowser for help on using the repository browser.