1
/* This file is part of "reprepro"
2
* Copyright (C) 2005,2006,2007,2009 Bernhard R. Link
3
* This program is free software; you can redistribute it and/or modify
4
* it under the terms of the GNU General Public License version 2 as
5
* published by the Free Software Foundation.
7
* This program is distributed in the hope that it will be useful,
8
* but WITHOUT ANY WARRANTY; without even the implied warranty of
9
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
* GNU General Public License for more details.
12
* You should have received a copy of the GNU General Public License
13
* along with this program; if not, write to the Free Software
14
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1301 USA
32
#include "signature.h"
33
#include "globmatch.h"
34
#include "uploaderslist.h"
36
struct upload_condition {
37
/* linked list of all sub-nodes */
38
/*@null@*/struct upload_condition *next;
40
enum upload_condition_type type;
41
const struct upload_condition *next_if_true, *next_if_false;
42
bool accept_if_true, accept_if_false;
44
/* none matching means false, at least one being from
45
* the set means true */
47
/* one not matching means false, otherwise true */
49
/* one not matching means false,
50
* otherwise true iff there is at least one */
52
/* having a candidate means true, otherwise false */
56
/* uc_SECTIONS, uc_BINARIES, uc_SOURCENAME, uc_BYHAND */
57
struct strlist strings;
58
/* uc_COMPONENTS, uc_ARCHITECTURES */
59
struct atomlist atoms;
62
struct upload_conditions {
63
/* condition currently tested */
64
const struct upload_condition *current;
65
/* current state of top most condition */
67
/* top most condition will not be true unless cleared*/
69
/* always use last next, then decrement */
71
const struct upload_condition *conditions[];
74
static retvalue upload_conditions_add(struct upload_conditions **c_p, const struct upload_condition *a) {
76
struct upload_conditions *n;
81
newcount = (*c_p)->count + 1;
82
n = realloc(*c_p, sizeof(struct upload_conditions)
83
+ newcount * sizeof(const struct upload_condition*));
88
n->conditions[newcount - 1] = a;
94
struct uploader *next;
96
char *reversed_fingerprint;
97
struct upload_condition permissions;
102
struct uploaders *next;
103
size_t reference_count;
107
struct uploader *by_fingerprint;
108
struct upload_condition anyvalidkeypermissions;
109
struct upload_condition unsignedpermissions;
110
struct upload_condition anybodypermissions;
111
} *uploaderslists = NULL;
113
static void uploadpermission_release(struct upload_condition *p) {
114
struct upload_condition *h, *f = NULL;
125
strlist_done(&p->strings);
128
case uc_ARCHITECTURES:
129
atomlist_done(&p->atoms);
137
/* next one must be freed: */
141
} while( p != NULL );
144
static void uploader_free(struct uploader *u) {
147
free(u->reversed_fingerprint);
148
uploadpermission_release(&u->permissions);
152
static void uploaders_free(struct uploaders *u) {
155
while( u->by_fingerprint != NULL ) {
156
struct uploader *next = u->by_fingerprint->next;
158
uploader_free(u->by_fingerprint);
159
u->by_fingerprint = next;
161
uploadpermission_release(&u->anyvalidkeypermissions);
162
uploadpermission_release(&u->anybodypermissions);
163
uploadpermission_release(&u->unsignedpermissions);
168
void uploaders_unlock(struct uploaders *u) {
169
if( u->reference_count > 1 ) {
170
u->reference_count--;
172
struct uploaders **p = &uploaderslists;
174
assert( u->reference_count == 1);
175
/* avoid double free: */
176
if( u->reference_count == 0 )
179
while( *p != NULL && *p != u )
181
assert( p != NULL && *p == u );
189
static retvalue find_key_and_add(struct uploaders *u, struct upload_conditions **c_p, const struct signature *s) {
190
size_t len, i, primary_len;
192
const char *fingerprint, *primary_fingerprint;
193
char *reversed_primary_key;
194
const struct uploader *uploader;
199
fingerprint = s->keyid;
200
assert( fingerprint != NULL );
201
len = strlen(fingerprint);
202
reversed = alloca(len+1);
203
if( reversed == NULL )
204
return RET_ERROR_OOM;
205
for( i = 0 ; i < len ; i++ ) {
206
char c = fingerprint[len-i-1];
207
if( c >= 'a' && c <= 'f' )
209
else if( c == 'x' && len-i-1 == 1 && fingerprint[0] == '0' )
211
if( ( c < '0' || c > '9' ) && ( c <'A' && c > 'F') ) {
213
"Strange character '%c'(=%hhu) in fingerprint '%s'.\n"
214
"Search for appropriate rules in the uploaders file might fail.\n",
221
reversed[len] = '\0';
223
/* hm, this only sees the key is expired when it is kind of late... */
224
primary_fingerprint = s->primary_keyid;
225
primary_len = strlen(primary_fingerprint);
226
reversed_primary_key = alloca(len+1);
227
if( FAILEDTOALLOC(reversed_primary_key) )
228
return RET_ERROR_OOM;
230
for( i = 0 ; i < primary_len ; i++ ) {
231
char c = primary_fingerprint[primary_len-i-1];
232
if( c >= 'a' && c <= 'f' )
234
else if( c == 'x' && primary_len-i-1 == 1 &&
235
primary_fingerprint[0] == '0' )
237
if( ( c < '0' || c > '9' ) && ( c <'A' && c > 'F') ) {
239
"Strange character '%c'(=%hhu) in fingerprint/key-id '%s'.\n"
240
"Search for appropriate rules in the uploaders file might fail.\n",
241
c, c, primary_fingerprint);
244
reversed_primary_key[i] = c;
247
reversed_primary_key[primary_len] = '\0';
249
for( uploader = u->by_fingerprint ; uploader != NULL ; uploader = uploader->next ) {
250
/* TODO: allow ignoring */
251
if( s->state != sist_valid )
253
if( uploader->allow_subkeys ) {
254
if( uploader->len > primary_len )
256
if( memcmp(uploader->reversed_fingerprint,
257
reversed_primary_key,
258
uploader->len) != 0 )
261
if( uploader->len > len )
263
if( memcmp(uploader->reversed_fingerprint,
264
reversed, uploader->len) != 0 )
267
r = upload_conditions_add(c_p, &uploader->permissions);
268
if( RET_WAS_ERROR(r) )
270
/* no break here, as a key might match
271
* multiple specifications of different length */
276
retvalue uploaders_permissions(struct uploaders *u, const struct signatures *signatures, struct upload_conditions **c_p) {
277
struct upload_conditions *conditions = NULL;
281
r = upload_conditions_add(&conditions,
282
&u->anybodypermissions);
283
if( RET_WAS_ERROR(r) )
285
if( signatures == NULL ) {
286
/* signatures.count might be 0 meaning there is
287
* something lile a gpg header but we could not get
288
* keys, because of a gpg error or because of being
289
* compiling without libgpgme */
290
r = upload_conditions_add(&conditions,
291
&u->unsignedpermissions);
292
if( RET_WAS_ERROR(r) ) {
297
if( signatures != NULL && signatures->validcount > 0 ) {
298
r = upload_conditions_add(&conditions,
299
&u->anyvalidkeypermissions);
300
if( RET_WAS_ERROR(r) ) {
305
if( signatures != NULL ) {
306
for( j = 0 ; j < signatures->count ; j++ ) {
307
r = find_key_and_add(u, &conditions,
308
&signatures->signatures[j]);
309
if( RET_WAS_ERROR(r) ) {
319
/* uc_FAILED means rejected, uc_ACCEPTED means can go in */
320
enum upload_condition_type uploaders_nextcondition(struct upload_conditions *c) {
322
if( c->current != NULL ) {
323
if( c->matching && !c->needscandidate ) {
324
if( c->current->accept_if_true )
326
c->current = c->current->next_if_true;
328
if( c->current->accept_if_false )
330
c->current = c->current->next_if_false;
334
/* return the first non-trivial one left: */
336
while( c->current != NULL ) {
337
assert( c->current->type > uc_REJECTED );
338
if( c->current->type == uc_ALWAYS ) {
339
if( c->current->accept_if_true )
341
c->current = c->current->next_if_true;
343
/* empty set fullfills all conditions,
344
but not an exists condition */
345
switch( c->current->needs ) {
348
c->needscandidate = false;
352
c->needscandidate = false;
354
case needs_existsall:
355
case needs_anycandidate:
357
c->needscandidate = true;
360
return c->current->type;
366
c->current = c->conditions[c->count];
371
static bool match_namecheck(const struct strlist *strings, const char *name) {
374
for( i = 0 ; i < strings->count ; i++ ) {
375
if( globmatch(name, strings->values[i]) )
381
bool uploaders_verifystring(struct upload_conditions *conditions, const char *name) {
382
const struct upload_condition *c = conditions->current;
385
assert( c->type == uc_BINARIES || c->type == uc_SECTIONS ||
386
c->type == uc_SOURCENAME || c->type == uc_BYHAND );
388
conditions->needscandidate = false;
389
switch( conditions->current->needs ) {
391
case needs_existsall:
392
/* once one condition is false, the case is settled */
394
if( conditions->matching &&
395
!match_namecheck(&c->strings, name) )
396
conditions->matching = false;
397
/* but while it is true, more info is needed */
398
return conditions->matching;
400
/* once one condition is true, the case is settled */
401
if( !conditions->matching &&
402
match_namecheck(&c->strings, name) )
403
conditions->matching = true;
404
conditions->needscandidate = false;
405
/* but while it is false, more info is needed */
406
return !conditions->matching;
407
case needs_anycandidate:
408
/* we are settled, no more information needed */
412
assert( conditions->current->needs != conditions->current->needs );
415
bool uploaders_verifyatom(struct upload_conditions *conditions, atom_t atom) {
416
const struct upload_condition *c = conditions->current;
419
assert( c->type == uc_ARCHITECTURES );
421
conditions->needscandidate = false;
422
switch( conditions->current->needs ) {
424
case needs_existsall:
425
/* once one condition is false, the case is settled */
427
if( conditions->matching &&
428
!atomlist_in(&c->atoms, atom) )
429
conditions->matching = false;
430
/* but while it is true, more info is needed */
431
return conditions->matching;
433
/* once one condition is true, the case is settled */
434
if( !conditions->matching &&
435
atomlist_in(&c->atoms, atom) )
436
conditions->matching = true;
437
/* but while it is false, more info is needed */
438
return !conditions->matching;
439
case needs_anycandidate:
440
/* we are settled, no more information needed */
444
assert( conditions->current->needs != conditions->current->needs );
447
static struct upload_condition *addfingerprint(struct uploaders *u, const char *fingerprint, size_t len, bool allow_subkeys) {
449
char *reversed = malloc(len+1);
450
struct uploader *uploader, **last;
452
if( reversed == NULL )
454
for( i = 0 ; i < len ; i++ ) {
455
char c = fingerprint[len-i-1];
456
if( c >= 'a' && c <= 'f' )
458
assert( ( c >= '0' && c <= '9' ) || ( c >= 'A' || c <= 'F') );
461
reversed[len] = '\0';
462
last = &u->by_fingerprint;
463
for( uploader = u->by_fingerprint ; uploader != NULL ; uploader = *(last = &uploader->next) ) {
464
if( uploader->len != len )
466
if( memcmp(uploader->reversed_fingerprint, reversed, len) != 0 )
468
if( uploader->allow_subkeys != allow_subkeys )
471
return &uploader->permissions;
473
assert( *last == NULL );
474
uploader = calloc(1,sizeof(struct uploader));
475
if( uploader == NULL )
478
uploader->reversed_fingerprint = reversed;
480
uploader->allow_subkeys = allow_subkeys;
481
return &uploader->permissions;
484
static inline const char *overkey(const char *p) {
485
while( (*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'f')
486
|| (*p >= 'A' && *p <= 'F') ) {
492
static retvalue parse_stringpart(/*@out@*/struct strlist *strings, const char **pp, const char *filename, long lineno, int column) {
496
strlist_init(strings);
498
const char *startp, *endp;
501
while( *p != '\0' && xisspace(*p) )
505
"%s:%lu:%u: starting \"'\" expected!\n",
506
filename, lineno, column + (int)(p-*pp));
511
while( *p != '\0' && *p != '\'' )
515
"%s:%lu:%u: closing \"'\" expected!\n",
516
filename, lineno, column + (int)(p-*pp));
519
assert( *p == '\'' );
522
n = strndup(startp, endp - startp);
523
if( FAILEDTOALLOC(n) )
524
return RET_ERROR_OOM;
525
r = strlist_adduniq(strings, n);
526
if( RET_WAS_ERROR(r) )
528
while( *p != '\0' && xisspace(*p) )
535
} while ( **pp == '|' );
540
static retvalue parse_architectures(/*@out@*/struct atomlist *atoms, const char **pp, const char *filename, long lineno, int column) {
544
atomlist_init(atoms);
546
const char *startp, *endp;
549
while( *p != '\0' && xisspace(*p) )
553
"%s:%lu:%u: starting \"'\" expected!\n",
554
filename, lineno, column + (int)(p-*pp));
559
while( *p != '\0' && *p != '\'' && *p != '*' && *p != '?' )
561
if( *p == '*' || *p == '?' ) {
563
"%s:%lu:%u: Wildcards are not allowed in architectures!\n",
564
filename, lineno, column + (int)(p-*pp));
569
"%s:%lu:%u: closing \"'\" expected!\n",
570
filename, lineno, column + (int)(p-*pp));
573
assert( *p == '\'' );
576
atom = architecture_find_l(startp, endp - startp);
577
if( !atom_defined(atom) ) {
579
"%s:%lu:%u: Unknown architecture '%.*s'! (Did you mistype?)\n",
581
column + (int)(startp-*pp),
582
(int)(endp-startp), startp);
585
r = atomlist_add_uniq(atoms, atom);
586
if( RET_WAS_ERROR(r) )
588
while( *p != '\0' && xisspace(*p) )
595
} while ( **pp == '|' );
600
static retvalue parse_condition(const char *filename, long lineno, int column, const char **pp, /*@out@*/struct upload_condition *condition) {
602
struct upload_condition *fallback, *last, *or_scope;
604
memset( condition, 0, sizeof(struct upload_condition));
606
/* allocate a new fallback-node:
607
* (this one is used to make it easier to concatenate those decision
608
* trees, especially it keeps open the possibility to have deny
610
fallback = calloc(1, sizeof(struct upload_condition));
611
if( FAILEDTOALLOC(fallback) )
612
return RET_ERROR_OOM;
613
fallback->type = uc_ALWAYS;
614
assert(!fallback->accept_if_true);
616
/* the queue with next has all nodes, so they can be freed
617
* (or otherwise modified) */
618
condition->next = fallback;
622
or_scope = condition;
625
if( strncmp(p, "not", 3) == 0 &&
628
while( *p != '\0' && xisspace(*p) )
630
/* negate means false is good and true
632
last->accept_if_false = true;
633
last->accept_if_true = false;
634
last->next_if_false = NULL;
635
last->next_if_true = fallback;
637
last->accept_if_false = false;
638
last->accept_if_true = true;
639
last->next_if_false = fallback;
640
last->next_if_true = NULL;
642
if( p[0] == '*' && xisspace(p[1]) ) {
643
last->type = uc_ALWAYS;
645
} else if( strncmp(p, "architectures", 13) == 0 &&
646
strchr(" \t'", p[13]) != NULL ) {
649
last->type = uc_ARCHITECTURES;
650
last->needs = needs_all;
652
while( *p != '\0' && xisspace(*p) )
654
if( strncmp(p, "contain", 7) == 0 &&
655
strchr(" \t'", p[7]) != NULL ) {
656
last->needs = needs_any;
660
r = parse_architectures(&last->atoms, &p,
663
if( RET_WAS_ERROR(r) ) {
664
uploadpermission_release(condition);
667
} else if( strncmp(p, "binaries", 8) == 0 &&
668
strchr(" \t'", p[8]) != NULL ) {
671
last->type = uc_BINARIES;
672
last->needs = needs_all;
674
while( *p != '\0' && xisspace(*p) )
676
if( strncmp(p, "contain", 7) == 0 &&
677
strchr(" \t'", p[7]) != NULL ) {
678
last->needs = needs_any;
682
r = parse_stringpart(&last->strings, &p,
685
if( RET_WAS_ERROR(r) ) {
686
uploadpermission_release(condition);
689
} else if( strncmp(p, "byhand", 6) == 0 &&
690
strchr(" \t'", p[6]) != NULL ) {
693
last->type = uc_BYHAND;
694
last->needs = needs_existsall;
696
while( *p != '\0' && xisspace(*p) )
699
strlist_init(&last->strings);
702
r = parse_stringpart(&last->strings, &p,
705
if( RET_WAS_ERROR(r) ) {
706
uploadpermission_release(condition);
709
} else if( strncmp(p, "sections", 8) == 0 &&
710
strchr(" \t'", p[8]) != NULL ) {
713
last->type = uc_SECTIONS;
714
last->needs = needs_all;
716
while( *p != '\0' && xisspace(*p) )
718
if( strncmp(p, "contain", 7) == 0 &&
719
strchr(" \t'", p[7]) != NULL ) {
720
last->needs = needs_any;
724
r = parse_stringpart(&last->strings, &p,
727
if( RET_WAS_ERROR(r) ) {
728
uploadpermission_release(condition);
731
} else if( strncmp(p, "source", 6) == 0 &&
732
strchr(" \t'", p[6]) != NULL ) {
735
last->type = uc_SOURCENAME;
738
r = parse_stringpart(&last->strings, &p,
741
if( RET_WAS_ERROR(r) ) {
742
uploadpermission_release(condition);
747
fprintf(stderr, "%s:%lu:%u: condition expected after 'allow' keyword!\n", filename, lineno, column + (int)(p-*pp));
748
uploadpermission_release(condition);
751
while( *p != '\0' && xisspace(*p) )
753
if( strncmp(p, "and", 3) == 0 && xisspace(p[3]) ) {
754
struct upload_condition *n, *c;
758
n = calloc(1, sizeof(struct upload_condition));
759
if( FAILEDTOALLOC(n) ) {
760
uploadpermission_release(condition);
761
return RET_ERROR_OOM;
763
/* everything that yet made it succeed makes it need
764
* to check this condition: */
765
for( c = condition ; c != NULL ; c = c->next ) {
766
if( c->accept_if_true ) {
768
c->accept_if_true = false;
770
if( c->accept_if_false ) {
771
c->next_if_false = n;
772
c->accept_if_false = false;
775
/* or will only bind to this one */
778
/* add it to queue: */
779
assert( last->next == fallback );
783
} else if( strncmp(p, "or", 2) == 0 && xisspace(p[2]) ) {
784
struct upload_condition *n, *c;
788
n = calloc(1, sizeof(struct upload_condition));
789
if( FAILEDTOALLOC(n) ) {
790
uploadpermission_release(condition);
791
return RET_ERROR_OOM;
793
/* everything in current scope that made it fail
794
* now makes it check this: (currently that will
795
* only be true at most for c == last, but with
796
* parantheses this all will be needed) */
797
for( c = or_scope ; c != NULL ; c = c->next ) {
798
if( c->next_if_true == fallback )
800
if( c->next_if_false == fallback )
801
c->next_if_false = n;
803
/* add it to queue: */
804
assert( last->next == fallback );
808
} else if( strncmp(p, "by", 2) == 0 && xisspace(p[2]) ) {
812
fprintf(stderr, "%s:%lu:%u: 'by','and' or 'or' keyword expected!\n", filename, (long)lineno, column + (int)(p-*pp));
813
uploadpermission_release(condition);
814
memset( condition, 0, sizeof(struct upload_condition));
817
while( *p != '\0' && xisspace(*p) )
824
static void condition_add(struct upload_condition *permissions, struct upload_condition *c) {
825
if( permissions->next == NULL ) {
826
/* first condition, as no fallback yet allocated */
828
memset(c, 0, sizeof(struct upload_condition));
830
struct upload_condition *last;
832
last = permissions->next;
833
assert( last != NULL );
834
while( last->next != NULL )
837
/* the very last is always the fallback-node to which all
838
* other conditions fall back if they have no decision */
839
assert(last->type = uc_ALWAYS);
840
assert(!last->accept_if_true);
843
memset(c, 0, sizeof(struct upload_condition));
847
static inline retvalue parseuploaderline(char *buffer, const char *filename, size_t lineno, struct uploaders *u) {
849
const char *p, *q, *qq;
851
struct upload_condition *permissions;
852
struct upload_condition condition;
857
if( buffer[l-1] != '\n' ) {
859
fprintf(stderr, "%s:%lu:1024: Overlong line!\n", filename, (long)lineno);
861
fprintf(stderr, "%s:%lu:%lu: Unterminated line!\n", filename, (long)lineno,(long)l);
866
} while( l > 0 && xisspace(buffer[l-1]) );
869
while( *p != '\0' && xisspace(*p) )
871
if( *p == '\0' || *p == '#' )
874
if( strncmp(p,"allow",5) != 0 || !xisspace(p[5]) ) {
875
fprintf(stderr, "%s:%lu:%u: 'allow' keyword expected! (no other statement has yet been implemented)\n", filename, (long)lineno, (int)(1+p-buffer));
879
while( *p != '\0' && xisspace(*p) )
881
r = parse_condition(filename, lineno, (1+p-buffer), &p, &condition);
882
if( RET_WAS_ERROR(r) )
884
while( *p != '\0' && xisspace(*p) )
886
if( strncmp(p,"key",3) == 0 && (p[3] == '\0' || xisspace(p[3])) ) {
887
bool allow_subkeys = false;
890
while( *p != '\0' && xisspace(*p) )
892
if( p[0] == '0' && p[1] == 'x' )
895
if( *p == '\0' || (*q !='\0' && !xisspace(*q) && *q != '+') || q==p ) {
896
fprintf(stderr, "%s:%lu:%u: key id or fingerprint expected!\n", filename, (long)lineno, (int)(1+q-buffer));
900
while( xisspace(*qq) )
904
allow_subkeys = true;
906
while( xisspace(*qq) )
909
fprintf(stderr, "%s:%lu:%u: unexpected data after 'key <fingerprint>' statement!\n\n", filename, (long)lineno, (int)(1+qq-buffer));
911
fprintf(stderr, " Hint: no spaces allowed in fingerprint specification.\n");
914
permissions = addfingerprint(u, p, q-p, allow_subkeys);
915
if( permissions == NULL )
916
return RET_ERROR_OOM;
917
condition_add(permissions, &condition);
918
} else if( strncmp(p, "unsigned",8) == 0 && (p[8]=='\0' || xisspace(p[8])) ) {
921
fprintf(stderr, "%s:%lu:%u: unexpected data after 'unsigned' statement!\n", filename, (long)lineno, (int)(1+p-buffer));
924
condition_add(&u->unsignedpermissions, &condition);
925
} else if( strncmp(p, "any",3) == 0 && xisspace(p[3]) ) {
927
while( *p != '\0' && xisspace(*p) )
929
if( strncmp(p, "key", 3) != 0 || (p[3]!='\0' && !xisspace(p[3])) ) {
930
fprintf(stderr, "%s:%lu:%u: 'key' keyword expected after 'any' keyword!\n", filename, (long)lineno, (int)(1+p-buffer));
935
fprintf(stderr, "%s:%lu:%u: unexpected data after 'any key' statement!\n", filename, (long)lineno, (int)(1+p-buffer));
938
condition_add(&u->anyvalidkeypermissions, &condition);
939
} else if( strncmp(p, "anybody", 7) == 0 && (p[7] == '\0' || xisspace(p[7])) ) {
941
while( *p != '\0' && xisspace(*p) )
944
fprintf(stderr, "%s:%lu:%u: unexpected data after 'anybody' statement!\n", filename, (long)lineno, (int)(1+p-buffer));
947
condition_add(&u->anybodypermissions, &condition);
949
fprintf(stderr, "%s:%lu:%u: 'key', 'unsigned', 'anybody' or 'any key' expected!\n", filename, (long)lineno, (int)(1+p-buffer));
955
static retvalue uploaders_load(/*@out@*/struct uploaders **list, const char *filename) {
956
char *fullfilename = NULL;
963
if( filename[0] != '/' ) {
964
fullfilename = calc_conffile(filename);
965
if( fullfilename == NULL )
966
return RET_ERROR_OOM;
967
filename = fullfilename;
969
f = fopen(filename, "r");
972
fprintf(stderr, "Error opening '%s': %s\n", filename, strerror(e));
976
u = calloc(1,sizeof(struct uploaders));
977
if( FAILEDTOALLOC(u) ) {
980
return RET_ERROR_OOM;
982
/* reject by default */
983
u->unsignedpermissions.type = uc_ALWAYS;
984
u->anyvalidkeypermissions.type = uc_ALWAYS;
985
u->anybodypermissions.type = uc_ALWAYS;
987
while( fgets(buffer,1024,f) != NULL ) {
989
r = parseuploaderline(buffer,filename,lineno,u);
990
if( RET_WAS_ERROR(r) ) {
997
if( fclose(f) != 0 ) {
999
fprintf(stderr, "Error reading '%s': %s\n", filename, strerror(e));
1002
return RET_ERRNO(e);
1009
retvalue uploaders_get(/*@out@*/struct uploaders **list, const char *filename) {
1011
struct uploaders *u;
1014
assert( filename != NULL );
1016
len = strlen(filename);
1018
while( u != NULL && ( u->filename_len != len ||
1019
memcmp(u->filename,filename,len) != 0 ) )
1022
r = uploaders_load(&u, filename);
1025
assert( u != NULL );
1026
u->filename = strdup(filename);
1027
if( u->filename == NULL ) {
1029
return RET_ERROR_OOM;
1031
u->filename_len = len;
1032
u->next = uploaderslists;
1033
u->reference_count = 1;
1036
u->reference_count++;