Fossil SCM

Begin adding the ability to restrict self-registration to people with a particular email address pattern. This check-in provides the setting to specify the authorized email addresses, but an attacker can still lie about his email address and sneak in that way. Still a work-in-progress.

drh 2020-04-23 18:36 trunk
Commit 7916dbaa03f6b8151cfb94ddb7663939bd581592cb52dc23636639c049c9a76d
+30
--- src/login.c
+++ src/login.c
@@ -1459,10 +1459,37 @@
14591459
"SELECT 1 FROM event WHERE user=%Q OR euser=%Q",
14601460
zUserID, zUserID, zUserID
14611461
);
14621462
return rc;
14631463
}
1464
+
1465
+/*
1466
+** Check an email address and confirm that it is valid for self-registration.
1467
+** The email address is known already to be well-formed.
1468
+**
1469
+** The default behavior is that any valid email address is accepted.
1470
+** But if the "self-reg-email" setting exists and is not empty, then
1471
+** it is a comma-separated list of GLOB patterns for email addresses
1472
+** that are authorized to self-register.
1473
+*/
1474
+static int authorized_self_register_email(const char *zEAddr){
1475
+ char *zGlob = db_get("self-reg-email",0);
1476
+ Glob *pGlob;
1477
+ char *zAddr;
1478
+ int rc;
1479
+
1480
+ if( zGlob==0 || zGlob[0]==0 ) return 1;
1481
+ zGlob = fossil_strtolwr(fossil_strdup(zGlob));
1482
+ pGlob = glob_create(zGlob);
1483
+ fossil_free(zGlob);
1484
+
1485
+ zAddr = fossil_strtolwr(fossil_strdup(zEAddr));
1486
+ rc = glob_match(pGlob, zAddr);
1487
+ fossil_free(zAddr);
1488
+ glob_free(pGlob);
1489
+ return rc!=0;
1490
+}
14641491
14651492
/*
14661493
** WEBPAGE: register
14671494
**
14681495
** Page to allow users to self-register. The "self-register" setting
@@ -1521,10 +1548,13 @@
15211548
iErrLine = 3;
15221549
zErr = "Required";
15231550
}else if( email_address_is_valid(zEAddr,0)==0 ){
15241551
iErrLine = 3;
15251552
zErr = "Not a valid email address";
1553
+ }else if( authorized_self_register_email(zEAddr)==0 ){
1554
+ iErrLine = 3;
1555
+ zErr = "Not an authorized email address";
15261556
}else if( strlen(zPasswd)<6 ){
15271557
iErrLine = 4;
15281558
zErr = "Password must be at least 6 characters long";
15291559
}else if( fossil_strcmp(zPasswd,zConfirm)!=0 ){
15301560
iErrLine = 5;
15311561
--- src/login.c
+++ src/login.c
@@ -1459,10 +1459,37 @@
1459 "SELECT 1 FROM event WHERE user=%Q OR euser=%Q",
1460 zUserID, zUserID, zUserID
1461 );
1462 return rc;
1463 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1464
1465 /*
1466 ** WEBPAGE: register
1467 **
1468 ** Page to allow users to self-register. The "self-register" setting
@@ -1521,10 +1548,13 @@
1521 iErrLine = 3;
1522 zErr = "Required";
1523 }else if( email_address_is_valid(zEAddr,0)==0 ){
1524 iErrLine = 3;
1525 zErr = "Not a valid email address";
 
 
 
1526 }else if( strlen(zPasswd)<6 ){
1527 iErrLine = 4;
1528 zErr = "Password must be at least 6 characters long";
1529 }else if( fossil_strcmp(zPasswd,zConfirm)!=0 ){
1530 iErrLine = 5;
1531
--- src/login.c
+++ src/login.c
@@ -1459,10 +1459,37 @@
1459 "SELECT 1 FROM event WHERE user=%Q OR euser=%Q",
1460 zUserID, zUserID, zUserID
1461 );
1462 return rc;
1463 }
1464
1465 /*
1466 ** Check an email address and confirm that it is valid for self-registration.
1467 ** The email address is known already to be well-formed.
1468 **
1469 ** The default behavior is that any valid email address is accepted.
1470 ** But if the "self-reg-email" setting exists and is not empty, then
1471 ** it is a comma-separated list of GLOB patterns for email addresses
1472 ** that are authorized to self-register.
1473 */
1474 static int authorized_self_register_email(const char *zEAddr){
1475 char *zGlob = db_get("self-reg-email",0);
1476 Glob *pGlob;
1477 char *zAddr;
1478 int rc;
1479
1480 if( zGlob==0 || zGlob[0]==0 ) return 1;
1481 zGlob = fossil_strtolwr(fossil_strdup(zGlob));
1482 pGlob = glob_create(zGlob);
1483 fossil_free(zGlob);
1484
1485 zAddr = fossil_strtolwr(fossil_strdup(zEAddr));
1486 rc = glob_match(pGlob, zAddr);
1487 fossil_free(zAddr);
1488 glob_free(pGlob);
1489 return rc!=0;
1490 }
1491
1492 /*
1493 ** WEBPAGE: register
1494 **
1495 ** Page to allow users to self-register. The "self-register" setting
@@ -1521,10 +1548,13 @@
1548 iErrLine = 3;
1549 zErr = "Required";
1550 }else if( email_address_is_valid(zEAddr,0)==0 ){
1551 iErrLine = 3;
1552 zErr = "Not a valid email address";
1553 }else if( authorized_self_register_email(zEAddr)==0 ){
1554 iErrLine = 3;
1555 zErr = "Not an authorized email address";
1556 }else if( strlen(zPasswd)<6 ){
1557 iErrLine = 4;
1558 zErr = "Password must be at least 6 characters long";
1559 }else if( fossil_strcmp(zPasswd,zConfirm)!=0 ){
1560 iErrLine = 5;
1561
+14 -1
--- src/setup.c
+++ src/setup.c
@@ -503,15 +503,28 @@
503503
@ <hr />
504504
onoff_attribute("Allow users to register themselves",
505505
"self-register", "selfregister", 0, 0);
506506
@ <p>Allow users to register themselves through the HTTP UI.
507507
@ The registration form always requires filling in a CAPTCHA
508
- @ (<em>auto-captcha</em> setting is ignored). Still, bear in mind that anyone
508
+ @ (<em>auto-captcha</em> setting is ignored). Keep in mind that anyone
509509
@ can register under any user name. This option is useful for public projects
510510
@ where you do not want everyone in any ticket discussion to be named
511511
@ "Anonymous". (Property: "self-register")</p>
512512
513
+ @ <hr />
514
+ entry_attribute("Authorized self-registration email addresses", 35,
515
+ "self-reg-email", "selfregemail", "", 0);
516
+ @ <p>This is a comma-separated list of GLOB patterns that specify
517
+ @ email addresses that are authorized to self-register. If blank
518
+ @ (the usual case), then any email address can be used to self-register.
519
+ @ This setting is used to limit self-registration to members of a particular
520
+ @ organization or group based on their email address. For example,
521
+ @ if the pattern is "<tt>*@megacorp.com, *@af.mil.to</tt>" then
522
+ @ only employees of MegaCorp and members of the Tonganese airforce
523
+ @ can self-register.
524
+ @ (Property: "self-reg-email")</p>
525
+
513526
@ <hr />
514527
entry_attribute("Default privileges", 10, "default-perms",
515528
"defaultperms", "u", 0);
516529
@ <p>Permissions given to users that... <ul><li>register themselves using
517530
@ the self-registration procedure (if enabled), or <li>access "public"
518531
--- src/setup.c
+++ src/setup.c
@@ -503,15 +503,28 @@
503 @ <hr />
504 onoff_attribute("Allow users to register themselves",
505 "self-register", "selfregister", 0, 0);
506 @ <p>Allow users to register themselves through the HTTP UI.
507 @ The registration form always requires filling in a CAPTCHA
508 @ (<em>auto-captcha</em> setting is ignored). Still, bear in mind that anyone
509 @ can register under any user name. This option is useful for public projects
510 @ where you do not want everyone in any ticket discussion to be named
511 @ "Anonymous". (Property: "self-register")</p>
512
 
 
 
 
 
 
 
 
 
 
 
 
 
513 @ <hr />
514 entry_attribute("Default privileges", 10, "default-perms",
515 "defaultperms", "u", 0);
516 @ <p>Permissions given to users that... <ul><li>register themselves using
517 @ the self-registration procedure (if enabled), or <li>access "public"
518
--- src/setup.c
+++ src/setup.c
@@ -503,15 +503,28 @@
503 @ <hr />
504 onoff_attribute("Allow users to register themselves",
505 "self-register", "selfregister", 0, 0);
506 @ <p>Allow users to register themselves through the HTTP UI.
507 @ The registration form always requires filling in a CAPTCHA
508 @ (<em>auto-captcha</em> setting is ignored). Keep in mind that anyone
509 @ can register under any user name. This option is useful for public projects
510 @ where you do not want everyone in any ticket discussion to be named
511 @ "Anonymous". (Property: "self-register")</p>
512
513 @ <hr />
514 entry_attribute("Authorized self-registration email addresses", 35,
515 "self-reg-email", "selfregemail", "", 0);
516 @ <p>This is a comma-separated list of GLOB patterns that specify
517 @ email addresses that are authorized to self-register. If blank
518 @ (the usual case), then any email address can be used to self-register.
519 @ This setting is used to limit self-registration to members of a particular
520 @ organization or group based on their email address. For example,
521 @ if the pattern is "<tt>*@megacorp.com, *@af.mil.to</tt>" then
522 @ only employees of MegaCorp and members of the Tonganese airforce
523 @ can self-register.
524 @ (Property: "self-reg-email")</p>
525
526 @ <hr />
527 entry_attribute("Default privileges", 10, "default-perms",
528 "defaultperms", "u", 0);
529 @ <p>Permissions given to users that... <ul><li>register themselves using
530 @ the self-registration procedure (if enabled), or <li>access "public"
531
+1 -11
--- src/url.c
+++ src/url.c
@@ -66,20 +66,10 @@
6666
int proxyOrigPort; /* Tunneled port number for https through proxy */
6767
};
6868
#endif /* INTERFACE */
6969
7070
71
-/*
72
-** Convert a string to lower-case.
73
-*/
74
-static void url_tolower(char *z){
75
- while( *z ){
76
- *z = fossil_tolower(*z);
77
- z++;
78
- }
79
-}
80
-
8171
/*
8272
** Parse the given URL. Populate members of the provided UrlData structure
8373
** as follows:
8474
**
8575
** isFile True if FILE:
@@ -177,11 +167,11 @@
177167
pUrlData->name++;
178168
pUrlData->name[n-2] = 0;
179169
}
180170
zLogin = mprintf("");
181171
}
182
- url_tolower(pUrlData->name);
172
+ fossil_strtolwr(pUrlData->name);
183173
if( c==':' ){
184174
pUrlData->port = 0;
185175
i++;
186176
while( (c = zUrl[i])!=0 && fossil_isdigit(c) ){
187177
pUrlData->port = pUrlData->port*10 + c - '0';
188178
--- src/url.c
+++ src/url.c
@@ -66,20 +66,10 @@
66 int proxyOrigPort; /* Tunneled port number for https through proxy */
67 };
68 #endif /* INTERFACE */
69
70
71 /*
72 ** Convert a string to lower-case.
73 */
74 static void url_tolower(char *z){
75 while( *z ){
76 *z = fossil_tolower(*z);
77 z++;
78 }
79 }
80
81 /*
82 ** Parse the given URL. Populate members of the provided UrlData structure
83 ** as follows:
84 **
85 ** isFile True if FILE:
@@ -177,11 +167,11 @@
177 pUrlData->name++;
178 pUrlData->name[n-2] = 0;
179 }
180 zLogin = mprintf("");
181 }
182 url_tolower(pUrlData->name);
183 if( c==':' ){
184 pUrlData->port = 0;
185 i++;
186 while( (c = zUrl[i])!=0 && fossil_isdigit(c) ){
187 pUrlData->port = pUrlData->port*10 + c - '0';
188
--- src/url.c
+++ src/url.c
@@ -66,20 +66,10 @@
66 int proxyOrigPort; /* Tunneled port number for https through proxy */
67 };
68 #endif /* INTERFACE */
69
70
 
 
 
 
 
 
 
 
 
 
71 /*
72 ** Parse the given URL. Populate members of the provided UrlData structure
73 ** as follows:
74 **
75 ** isFile True if FILE:
@@ -177,11 +167,11 @@
167 pUrlData->name++;
168 pUrlData->name[n-2] = 0;
169 }
170 zLogin = mprintf("");
171 }
172 fossil_strtolwr(pUrlData->name);
173 if( c==':' ){
174 pUrlData->port = 0;
175 i++;
176 while( (c = zUrl[i])!=0 && fossil_isdigit(c) ){
177 pUrlData->port = pUrlData->port*10 + c - '0';
178
+15
--- src/util.c
+++ src/util.c
@@ -140,10 +140,25 @@
140140
}
141141
#else
142142
fossil_free(p);
143143
#endif
144144
}
145
+
146
+/*
147
+** Translate every upper-case character in the input string into
148
+** its equivalent lower-case.
149
+*/
150
+char *fossil_strtolwr(char *zIn){
151
+ char *zStart = zIn;
152
+ if( zIn ){
153
+ while( *zIn ){
154
+ *zIn = fossil_tolower(*zIn);
155
+ zIn++;
156
+ }
157
+ }
158
+ return zStart;
159
+}
145160
146161
/*
147162
** This function implements a cross-platform "system()" interface.
148163
*/
149164
int fossil_system(const char *zOrigCmd){
150165
--- src/util.c
+++ src/util.c
@@ -140,10 +140,25 @@
140 }
141 #else
142 fossil_free(p);
143 #endif
144 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
146 /*
147 ** This function implements a cross-platform "system()" interface.
148 */
149 int fossil_system(const char *zOrigCmd){
150
--- src/util.c
+++ src/util.c
@@ -140,10 +140,25 @@
140 }
141 #else
142 fossil_free(p);
143 #endif
144 }
145
146 /*
147 ** Translate every upper-case character in the input string into
148 ** its equivalent lower-case.
149 */
150 char *fossil_strtolwr(char *zIn){
151 char *zStart = zIn;
152 if( zIn ){
153 while( *zIn ){
154 *zIn = fossil_tolower(*zIn);
155 zIn++;
156 }
157 }
158 return zStart;
159 }
160
161 /*
162 ** This function implements a cross-platform "system()" interface.
163 */
164 int fossil_system(const char *zOrigCmd){
165

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button