List of commits:
Subject Hash Author Date (UTC)
Lots of changes, but mostly LDAP support 029d34fdc14587b9ef6eb9e87ac36f66caefdacf Catalin(ux) M. BOIE 2017-11-24 19:35:59
Fix state bug which triggered a not needed update of the structure f6118c456bfc960782a53b9dc090046d542f9db9 Catalin(ux) M. BOIE 2017-11-24 19:12:38
Some free_result and unlock only if successfully locked 64666ca1371c004f74376fce2e2a67ee9f608a34 Catalin(ux) M. BOIE 2017-10-01 06:10:47
If git_log_simple returns error, just return error acbbacda0947a3f8496c9b15870db574c08db715 Catalin(ux) M. BOIE 2017-08-31 03:43:25
Be less verbose in rg_rights_test 3cb2d12960b059b61f7c2c47c6198fbbdee8bccd Catalin(ux) M. BOIE 2017-08-10 04:19:34
Remove rg_log_buf stuff because of performance issues e85f70b38c197d44a9b4878dcff78da4f4f56562 Catalin(ux) M. BOIE 2017-08-08 20:08:56
Use a more efficient way to log multi line strings 67923e6760bf26923bd7ce9c9bced7a3f526cecf Catalin(ux) M. BOIE 2017-08-08 19:54:00
css: make border more visible 378b328cde875d1584f3df6d8635b340ee23207a Catalin(ux) M. BOIE 2017-07-22 23:27:29
struct: add itime for commit_labels 67d189b9d3330ab4dc3b6a0580a736522b6c1d36 Catalin(ux) M. BOIE 2017-07-22 23:05:02
wh: builder: we need repo info for clone_url_ssh info 6e95861b22476b0857f98a49025fc060302c2a3f Catalin(ux) M. BOIE 2017-07-22 12:35:52
hints: ssh: make more clear that ssh must be restarted 8c35f89b323d3ea28fad79f4c32d78aadc8618f6 Catalin(ux) M. BOIE 2017-07-22 08:17:37
rg_authorize must be run as rocketgit user - fix permissions to 0755 80db46ae953b72ba521b3cd96c91602e127fc8f8 Catalin(ux) M. BOIE 2017-07-22 08:07:56
build_jobs: Columns with no defaults must be specified bbb1c0036be3c6180d84e0641f41aa60ae1905f1 Catalin(ux) M. BOIE 2017-07-20 20:34:32
Show the suggestion to use https correctly 9656ff5ec3bfe65fc7a573fae254483c31d88501 Catalin(ux) M. BOIE 2017-07-10 20:57:26
rg_template_eval_cond: now supports more operations 2155bedec6e82343d84c8c504c0beb68fdf01dea Catalin(ux) M. BOIE 2017-07-10 20:55:48
Minor corrections dc3ce904f00ce5903ac5614ac870a0529d22ee4a Catalin(ux) M. BOIE 2017-07-10 20:55:03
state_get: Return empty if the state table does not exists 35822bff104ba2133f29a0a69cff4603d990a721 Catalin(ux) M. BOIE 2017-07-09 19:18:11
duilder: add 'samples' dir to the docs 8762f7dbfcec1f3ed5d6d7ba7dbf0ed547a894b7 Catalin(ux) M. BOIE 2017-07-09 06:54:06
Bump version to 0.70 a3524c87b21d22d734626503683e80e51abd574c Catalin(ux) M. BOIE 2017-07-09 06:40:24
Added nginx next to apache 982e6536f5204a07c939b01229784a46c18cdada Catalin(ux) M. BOIE 2017-07-09 06:38:55
Commit 029d34fdc14587b9ef6eb9e87ac36f66caefdacf - Lots of changes, but mostly LDAP support
Author: Catalin(ux) M. BOIE
Author date (UTC): 2017-11-24 19:35
Committer name: Catalin(ux) M. BOIE
Committer date (UTC): 2017-11-24 20:03
Parent(s): f6118c456bfc960782a53b9dc090046d542f9db9
Signer:
Signing key:
Signing status: N
Tree: f6744b89b24b072e845826bff2af4d07b7c326b5
File Lines added Lines deleted
TODO 414 38
compare.csv 3 3
inc/admin.inc.php 0 1
inc/admin/admin.php 5 1
inc/admin/plans/plans.php 1 1
inc/api.inc.php 0 1
inc/builder.inc.php 6 3
inc/events.inc.php 4 0
inc/git.inc.php 14 6
inc/ldap.inc.php 706 0
inc/ldap_core.inc.php 252 0
inc/ldap_sync.inc.php 448 0
inc/log.inc.php 8 3
inc/login/login.php 2 2
inc/plan.inc.php 20 17
inc/repo.inc.php 17 15
inc/sql.inc.php 132 36
inc/ssh.inc.php 2 2
inc/struct.inc.php 46 1
inc/token.inc.php 2 4
inc/user.inc.php 314 106
inc/util.inc.php 300 5
inc/wh/amazon.inc.php 4 4
inc/wh/build.inc.php 2 2
inc/wh/cloud.inc.php 2 2
inc/wh/lambda.inc.php 1 1
root/index.php 1 0
root/themes/default/admin/ldap/add_edit.html 90 0
root/themes/default/admin/ldap/add_ok.html 0 0
root/themes/default/admin/ldap/delete_err.html 1 0
root/themes/default/admin/ldap/delete_ok.html 3 0
root/themes/default/admin/ldap/edit_ok.html 0 0
root/themes/default/admin/ldap/hints.html 6 0
root/themes/default/admin/ldap/list/footer.html 4 0
root/themes/default/admin/ldap/list/header.html 25 0
root/themes/default/admin/ldap/list/line.html 20 0
root/themes/default/admin/ldap/list/nodata.html 1 1
root/themes/default/admin/ldap/list_err.html 1 0
root/themes/default/admin/ldap/menu.html 6 0
root/themes/default/admin/menu.html 1 0
root/themes/default/admin/plans/delete_err.html 1 1
root/themes/default/admin/settings/web/hints.html 1 1
samples/nginx.conf 5 9
samples/pool.conf 1 1
scripts/remote.php 13 9
scripts/worker.php 58 28
tests/Makefile 2 1
tests/_run_tests.sh 2 1
tests/admin_set_git.php 6 2
tests/admin_set_web.php 6 2
tests/config.php 2 1
tests/helpers.inc.php 0 1
tests/http.inc.php 6 0
tests/http_keys.php 6 2
tests/ldap.php 506 0
tests/ldap/.gitignore 4 0
tests/ldap/1.php 47 0
tests/ldap/README 13 0
tests/ldap/add_user.sh 15 0
tests/ldap/conf.tmpl/cn=config.ldif 15 0
tests/ldap/conf.tmpl/cn=config/cn=schema.ldif 12 0
tests/ldap/conf.tmpl/cn=config/cn=schema/cn={0}core.ldif 249 0
tests/ldap/conf.tmpl/cn=config/olcDatabase={-1}frontend.ldif 12 0
tests/ldap/conf.tmpl/cn=config/olcDatabase={0}config.ldif 15 0
tests/ldap/conf.tmpl/cn=config/olcDatabase={1}monitor.ldif 14 0
tests/ldap/conf.tmpl/cn=config/olcDatabase={2}mdb.ldif 18 0
tests/ldap/dump-anon.sh 6 0
tests/ldap/dump-slapcat.sh 1 0
tests/ldap/dump.sh 9 0
tests/ldap/dump_syncrepl_ro.sh 19 0
tests/ldap/dump_syncrepl_rp.sh 17 0
tests/ldap/get_ContextCSN.sh 11 0
tests/ldap/naming.sh 2 0
tests/ldap/prepare.sh 270 0
tests/ldap/start.sh 17 0
tests/ldap_core.php 74 0
tests/ldap_core1.ldif 46 0
tests/log.php 28 0
tests/repo.php 2 0
tests/rights.php 0 2
tests/sql-fork.php 53 0
tests/sql.php 54 6
tests/token.php 3 0
tests/user.php 0 2
tests/util.php 102 0
File TODO changed (mode: 100644) (index 259c7b1..8daa2f2)
1 1 == Where I stopped last time == == Where I stopped last time ==
2 [ ]
2 [ ] ldap: func test when ldap_password changes, but we have the user inserted
3 in 'users'
4 [ ] Will the moving of user_edit_no_check call into ldap would simplify code?
5 [ ] Can I update users.plan_id on demand, when user logs in?
6 No, because the statistics are not good!
7 [ ] If we change the 'uid' attribute, we must invalidate the whole cache.
8 But, we cannot delete anything. We need the link between uuid and uid.
9 Just mark it as unavailable.
10 [ ] Recover password must be enabled for ldap users?
11 [ ] 'deleted' field must be respected by ldap?
12 If admin blocks/deletes/suspends an ldap account, what should we do?
13 [ ] I think I should not allow the login by e-mail! If user can change the
14 e-mail in LDAP, I have a problem. I think I can keep it.
15 The password must match. Check!
16 What about recovering e-mail?
17 [ ] memberof must be stored in ldap_cache.
18 [ ] rg_ldap_session_time to be set by the ldap server add form.
19 [ ] Password must be sent encrypted from ldap_cache to 'users' (update_no_check)).
20 [ ] When getting data from cache, I have to populate correctly the $ui.
21 It is a valid case for replication: we will have entries in
22 ldap_cache with 'uid' 0.
23 [ ] ldap: we do not have the membership and we cannot extract is_admin.
24 Probably other fields.
25 [ ] ldap: ce se intimpla daca schimb cimpul 'uid'? Sa permit asta?
26 Probably I have to clean the cache.
27 Because I do not store all fields in cache and the new uid field
28 probably is missing. Maybe I should test if the field is present and
29 do not delete the cache? Neh... But, if I delete the cache, I lose
30 the links between 'users' and ldap_cache!
31 Mark the ldap_cache entries as 'stalled' and use them only to link to
32 uid?
33 [ ] ldap: default for uid_attr is uid?
34 [ ] ldap: what rights should I give for users added by ldap?
35 [ ] Pass also the ldap server info, next to 'post', to be able to update
36 plan_id.
37 [ ] ldap: ldap_login: user not found in cache, binding is ok, we are at the
38 end of the function. We should store $ui in cache, but we do not have
39 the users.uid! What to do?! Should I return $ui and insert the user
40 in users and call a callback to update the cache because we have the
41 users.uid? Should it be in a transaction?
42 So login_by_user_pass
43 try to find in in users.db
44 if not found
45 try to search it in ldap_cache
46 if not found
47 search on ldap server
48 if found
49 return $ui
50 now, we have $ui, but the uid may be 0
51 if 0
52 insert the new user in database
53 call a callback to update ldap_cache with the
54 uid.
55 should not be in transaction, because next
56 time we will return without uid and we will do
57 an insert into db. NOT GOOD! We must not
58 duplicate users (anyway, it wouldn't work).
59 So, we need a transaction. But, what happends
60 when we delete stuff from the ldap_cache?!
61 Should we mark the users as deleted?
62 Should I use the uuid to not update ldap_cache?
63
64 If I do link 'users' and 'ldap_cache' by uid:
65 I have to call a 'post' callback, in a transaction to also update ldap_cache.uid
66 Nope. Cannot work. Another login will try to insert the same username.
67 Transactions cannot help!
68
69 CPU1 CPU2
70 SELECT FROM users WHERE username = ...
71 SELECT FROM ldap_cache (not found)
72 SELECT FROM users WHERE username = ...
73 SELECT FROM ldap_cache (not found)
74 INSERT INTO users (ok)
75 INSERT INTO users (fail)
76
77 If I link them by uuid:
78 - No 'post' hook needed
79 - At login time, ldap_cache will give the uuid and I have to
80 search by it in users table. Ugly.
81 For both, I have to update users.username field if different. Event?
82
83 I can use an advisory lock.
84
85 Let's see what happens if I link by uuid:
86 first login: ldap_cache is emty
87 ldap_login is called
88 cache is empty, so I continue
89 bind correctly in ldap
90 insert into ldap_cache(..., uuid, ...)
91 return $ui with everything from ldap
92 insert into users with external_id = uuid
93 second login: ldap_cache has the user now
94 ldap_login is called
95 found in users
96 third login: users entry expired
97 found in users but is expired
98 ldap_login is called
99 return $ui with everything from ldap_cache
100
101 CPU1 CPU2 CPU3
102 SELECT FROM users (by username/pass)
103 SELECT FROM users (by username/pass)
104 SELECT FROM ldap_cache (by ?) (not found)
105 ldap_bind & co.
106 SELECT FROM ldap_cache (not found)
107 ldap_bind & co.
108 LOCK ldap_cache
109 LOCK ldap_cache
110 SELECT FROM ldap_cache (not found)
111 INSERT INTO users (ok) - to find the uid; nobody can do it concurrently!
112 INSERT INTO ldap_cache (...uid/uuid...)
113 UNLOCK ldap_cache
114 SELECT FROM ldap_cache (found) SELECT FROM users (by username/pass) (expired)
115 SELECT FROM ldap_cache (found)
116 UNLOCK ldap_cache
117
118 I should try to do a select in ldap_cache, if not found lock the table,
119 do again the select in ldap_cache (someone may insert between select and lock).
120 So, if found in cache, I will not lock the table.
121 One problem: I should not do the bind with the lock taken. Fixed.
122
123 If I use uuid, when the ldap_cache returns something, I have to do
124 a select in db after uuid to obtain the entry!
125 Another query, another index...
126
127 What if I would insert into ldap_cache, under lock and then return?
128 Then, two threads will try to insert into 'users'!
129
130 What if I link 'users' and 'ldap_cache' by username?!
3 131
132 === New plan: ignore 'duplicate unique' errors ===
133 CPU1
134 SELECT FROM users (by username/pass) (not found / expired)
135 SELECT FROM ldap_cache (by mail/ldap_uid/cn) (not found / expired)
136 contact ldap server (binding/search)
137 INSERT INTO ldap_cache (...uid/uuid...)
138 INSERT INTO users (ok) - to find the uid; ignore error
139 apelez un callback care face update la ldap_cache.uid?
140
141 Pot insera in cache prima data (ce se intimpla daca e deja? update?)
142 Problema e ca e posibil sa nu gasesc row-ul in 'users' ca
143 sa-i fac update si inserez unul nou. Ar trebui sa-l caut mai
144 intii. As putea face update si daca nu merge sa fac insert.
145 Dar, la update, ce WHERE folosesc? external_id?
146
147 [ ] ldap: we may want to check AuthLDAPGroupAttributeIsDN from apache.
148 [ ] ldap: should we have a 'source' field in users table to signal from where
149 the user come from (web, ldap etc.)?
150 [ ] ldap: When updating a server prio, we have to update also the ldap_cache
151 table. Should I use a JOIN to get rid of ldap_cache.prio?
152 [ ] ldap: Do not store password in clear in database!
153 [ ] ldap: add a timeout for every server.
154 [ ] ldap: gather all sync stuff and commit in the end for sync=ro?
155 [ ] ldap: take care to not allow logins as admins if the group name is user
156 controlled. Should we use ^/$ by default?
157 [ ] ldap: https://github.com/thorin/redmine_ldap_sync
158 As an example which works also on AD.
159 [ ] ldap: how to specify if an account is disabled? Some regex needed?
160 [ ] ldap: server settings: select between one level or subtree.
161 [ ] ldap: what indexes are needed for ldap_* tables?
162 [ ] ldap: Remember, I may have the full ldap db in ldap_cache table,
163 without a link with uid! When a ldap users login for the first time,
164 I can do the link (store uid in ldap_cache table).
165 [ ] ldap: I have to learn entryUUID now!
166 [ ] ldap: when a user logins, she/he uses the e-mail, or uid or something
167 decided by LDAP admin.
168 I have to identify the user in 'users'. How can I?
169 With a table containing:
170 server_id [3] - to be able to remove a server or to not have clashes?
171 uid [55] - may be 0 if the user did not logged in yet
172 ldap_uid [catalinux]
173 userPassword [] - we must be able to decrypt it using the same algo
174 sn
175 givenName
176 gidNumber
177 entryUUID [12345-12345-12345-12345-12345]
178 - to be used when sync data
179 mail [catalinux@rocketgit.com]
180 Do not forget about the groups!
181 When a user connects, I need to search by one of the ldap attributes
182 to obtain the uid, then:
183 if password is not valid, search next entry.
184 if ldap_cache.uid == 0, insert a new entry in 'users' table and update ldap_cache.uid
185 if ldap_cache.uid != 0, we have the uid
186 Can we optimize the search?
187 [] We should try another entry/server if the password does not match.
188 [ ] ldap: somehow delete old ldap servers. Also from cache.
189 [ ] ldap: test: login by email.
190 [ ] ldap: user logins by DN, and, of course, I cannot find it in the database.
191 I have to search for it based on entryUUID.
192 [ ] ldap: now the dilemma is how to add a user from inside ldap_login function!
193 Should we return a special flag which instructs the login function
194 to add the user?
195 [ ] ldap: what plan should have the users? Select it when adding the servers.
196 What if the plan is gone? Use the first one and notify admin?
197 [ ] ldap: now, what field will be the future username in db? uid? Configurable?
198 [ ] ldap: admin: add servers
199 Should we have a daemon to sync with the ldap server?
200 [ ] When upgrading and cache was not up, on rocketgit.com, logged in as admin
201 it asked about initial account! This is not good!
202 [ ] 'meronos' user is with lower 'm', but in the /var/lib/rocketgit/repos/
203 folder is with bigger M! Does he renamed the user and I did not updated
204 the link?
205 [ ] wh:build: output is not collected.
206 [ ] Lots of errors of this type:
207 16056 ? D 16:47 git --no-pager
208 --git-dir=/var/lib/rocketgit/repos/by_id/00/00/00/7B/0000007B/
209 repos/by_id/125.git log --find-copies --find-renames
210 --find-copies-harder --no-merges --numstat -z
211 --pretty=format:-=ROCKETGIT-START-5ab66aa6dd48474e=-sha1:%H%x00
212 sha1_short:%h%x00tree:%T%x00tree_short:%t%x00parents:%P%x00
213 parents_short:%p%x00author name:%aN%x00author email:%aE%x00
214 author date:%at%x00committer name:%cN%x00committer email:%ce%x00
215 committer date:%ct%x00encoding:%e%x00ref_names:%d%x00
216 sign_key:%GK%x00subject:%s%x00body:%b%x00notes:%N%x00
217 -=ROCKETGIT_END_OF_VARS-5ab66aa6dd48474e=-
218 [ ] Prevent repos to start with '-'? (Git security issue)
219 [ ] Allow download of files in the repo.
220 [ ] Username must not contain '::' to not break cache!
221 Hm. Any string containing :: is at risk?! Or the = makes the diff?
222 [ ] Plan for LDAP sync:
223 Should I have a different password in 'users' table for backup?
224 I have to create the users.
225 I have to take it step by step:
226 All posible LDAP servers are verified by priority
227 All servers have some flags (or a single) type:
228 - if a direct connection is made (with or without cache)
229 - if ro repl is used
230 - if rp repl is used
231 But, all may be used. ro/rp replications are pretty the same.
232 Direct connection should be used if anything fails.
233 The cache may be used only if admin decided on how many seconds
234 a cache is valid.
235 ro/rp repl should populate the cache only - a user must
236 not be created in db if the user did not login.
237 So, a user tries to login:
238 - check database - first time the user is not there
239 Second time?
240 Should we mark the entry as being ldap?
241 - go to ldap function
242 - select in ldap cache table if a user is matching (order prio)
243 - if not found, do a direct lookup
244 - update the database?
245 We must insert into database to obtain the uid.
246 The sync process will update the database if needed (entryUUID).
4 247
5 248 == BEFORE NEXT RELEASE == == BEFORE NEXT RELEASE ==
249 [ ] Add compression for JS/CSS. Think about enabling compression for html,
250 but, implement some randomization on content to defend against BREACH.
251 For CSRF tokens there is a simple and effective defence, which is to randomize the token by masking it with a different (random) value on every response. The masking does not hide the token (whoever has the token can easily reverse the masking), but it does defeat the attack technique. Guessing is impossible when the secret is changing all the time. Thus, we can expect that most frameworks will adopt this technique. Those who rely on frameworks will only need to upgrade to take advantage of the defence. Those who don’t will have to fix their code.
252 (https://blog.qualys.com/ssllabs/2013/08/07/defending-against-the-breach-attack)
253
254 [ ] Implement https://github.com/privacypass/challenge-bypass-extension
255 [ ] ldap: test nested groups.
256 [ ] 2fa: admin must be able to enforce it!
257 [ ] Have a user setting / button to create a diff without space clean-up.
258 [ ] detect big patches can return 'bad' and no good_files, but the simple log
259 is still called! Not good! Functional test!
260 [ ] Go to groups.google.com and create a group for rocketgit?
261 [ ] I like the forms on http://cc1.ifj.edu.pl/en/
262 [ ] Cache HTTP credentials:
263 git config --global credential.helper cache
264 [ ] Adopt DCO: https://developercertificate.org/
265 [ ] periodically run 'git fsck'.
266 [ ] ssh: 'UseDNS no' (docker / virtual machine etc.) to speed up the connection.
267 [ ]
268 [ ] Allow multiple branches in the pull request
269 [ ] Enable HTTP/2 (as the tests)!
270 [ ] ldap: what to do with the ldap users when their server is removed?
271 [ ] Add a hint to login page that, with ldap, you can login also with mail/cn.
272 [ ] Allow user to choose if the real name is public or not?
273 [ ] Support https://www.microcosm.co.uk/order/product.php?ProductID=360&CurrencyID=3
274 [ ] I should fail the test phase if err- files are generated?
275 What about server side?
276 [ ] Add labels for projects.
277 [ ] When creating a repo, refuse to end in '.git'. I strip it sometimes (tekker user)!
278 [ ] Get rid of links in /var/lib/rocketgit/repos, to not deal with renames etc.
279 [ ] I need a mechanism to verify an account expiration, even if a session
280 is active. Think about marking an account to expire at some moment
281 in time. We have shadowExpire for LDAP, but we must be able to do it
282 also for normal accounts. The field is 'expire'. And maybe give up on
283 'suspended' field?
284 Do we really test if an account is suspended?
285 Maybe is better to reuse 'suspended'.
286 [ ] Add timezone setting?
287 [ ] For authorize script, why we do not use the cache?
288 [ ] ldap: what session time to use? Use default, but let the user change?
289 [ ] Welcome e-mail may contain links to tutorials/api etc.
290 [ ] Should we store the server next to a ldap user to be able to look up
291 the timeout value? Or just store the expiration into users table?
292 What about entryUUID, the only thing that links ldap with db.
293 What if user is renamed? Should I give up on keeping links,
294 but, for admins, show the path to the repo.
295 [ ] ui['rights'] is still used? If yes, set them also for ldap.
296 [ ] Add a functional test to see if the request for e-mail confirmation is
297 shown on the page. And move it from hints to somewhere near the top.
298 [ ] ask_for_email_confirmation and rg_account_email_confirm do same thing?
299 [ ] Use sshd's ExposeAuthInfo to log some nice info.
300 [ ] We should never redirect using an empty string.
301 [ ] ldap: loop if password does not mach for an user.
302 [ ] ldap: when we find a user, try to bind as that user if first time
303 we bound with the main one.
304 [ ] preg_match may return an error. Test for it!
305 [ ] If I restart the builder server side script, the client will not reconnect!
306 [ ] compare: granting reverse endorse power? RocketGit: No; GitLab: yes.
307 [ ] Decide what to do about Frederico request for space.
308 [ ] Add to home/repo page hints that you can build (CI) your project.
309 [ ] wh: build: cloning with --depth 1 seems to not allow checking out a specific
310 commit. Not true. Seems a force push took place.
311 We should cancel previous builds?
312 [ ] ldap: sync ssh keys
313 [ ] ldap: timeout must also be a parameter.
314 [ ] ldap: forgot function should not work?
315 [ ] ldap: User changing group => dn changes
316 [ ] ldap: User changing dn - check if entryDN is of any help.
317 [ ] artefacts generated by demand, on a special page.
318 Think about building a CSV file from some files stored in repository.
319 For example: building a csv list of servers based on some directories
320 with the server and some files containing some info.
321 Of course, a sandbox is needed for this. Lua?
322 [ ] change log id on forking and log this change.
323 [ ] ldap: limit replication fields to the ones needed.
324 [ ] ldap: allow admin to move all users to a ldap server (including groups)
325 [ ] https://stackoverflow.com/questions/28810795/git-clone-is-aborting-due-to-possible-repository-corruption-on-the-remote-side-e/28811605#28811605
326 [ ] web: Add 'add_header Cache-Control "public";' to 'public' content
327 (nginx/location)
328 [ ] report: add also the load
329 [ ] Per git configuration, should be exposed to the user
330 gc.pruneExpire 2.weeks.ago
331 pack.*
332 [ ] css: add 'placeholder="some example here"' for some input fields.
333 [ ] In the report, show also the number of deleted repos.
334 [ ] We should not allow plan deletion if there are still users.
335 [ ] started requests without a final "commit" message should be logged as
336 errors. Think about git operations which does not finish because
337 PHP is out of memory. At the start and end of the operation we should
338 send a message. If the 'end' is missing, we know that something is
339 wrong.
340 [ ] We should re-think the logging, because some functions are
341 called multiple times (hundreds) and we do not want
342 the rg_log_enter string to appear multiple times.
343 We need to delay the logging somehow and log the pending buffer
344 only in case of errors.
345 [ ] Improve the caching of the rights.
346 [ ] rights: do not log success lookups, only the bad ones.
347 Too much logging involved!
348 [ ] Messages from ssh/http transport: log also date and rg_log_sid to be able
349 to find the problem quickly.
350 [ ] invite function for a repo - maybe suggest the rights?
351 Auto create user? (petreb)
352 [ ] Allow almost any file to be downloaded as pdf.
353 [ ] wh: build: add time for machine boot-up.
354 [ ] I have some broken links in the /var/lib/rocketgit/repos folder.
355 Maybe somebody deleted the repo? Check the logs.
356 [ ] ssh: wait till first connection is done with AuthorizedKeysCommand
357 and only after that disable the authorized_keys generation?
358 [ ] ldap: admin: allow switching between ldap and non-ldap accounts.
359 Because users may change their e-mail, we should be careful
360 what we use for ldap authentication.
361 Should we allow users to update an account to ldap?
362 [ ] ldap: allow admin to set ssl/starttls per server.
363 [ ] ldap: server add form:
364 - type of the server (can we auto detect?)
365 - host(s) urls (including port)
366 - bind_dn + pass
367 - base for search
368 - which ldap field is used for authentication (sAMAccountName/uid etc.)
369 - filter (&(objectClass=posixAccount)(uid=...)
370 we may need to support more user types (e.g. 'user')
371 - group base
372 - group attribute ('group', 'posixGroup', 'groupOfNames' etc.)
373 - admin group
374 - regex for what groups the users are allowed to use rocketgit
375 - mapping between ldap attributes and rocketgit user attributes
376 - if we allow ssh keys from ldap
377 - enable nested groups
378 - paged results
379 - follow referrals
380 - ca/certificate/key/insecure?
381 [ ] ldap: sync: use ldapsearch -E sync=ro/rp!
382 [ ] ldap: respect account expiration set in ldap (shadowExpire etc.)
383 [ ] ldap: we may allow rocketgit rights to be defined in ldap
384 [ ] ldap: allow admin to decide the time between syncs.
385 [ ] ldap: find a way to re-sync more quickly, maybe just looking up
386 only what changed since the last sync.
387 Or, use the replication protocol?
388 [ ] ldap: prevent users to change their settings if the account is linked
389 with ldap?
390 [ ] ldap:
391 http://mageconfig.blogspot.ro/2014/06/configure-gitgerrit-with-open-ldap-for.html
392 add groups support
393 [ ] a repo must have a direct link to report a bug.
394 [ ] Add a functional test for a max commit size bigger than a big number.
395 [ ] gabi: add API: input: user/pass, out: key for mobile app
396 [ ] gabi: API: discover, search etc.
397 [ ] In rg_exec, I can count how many bytes were sent/received!
398 Expose them in the ssh keys section?
399 Account them and enfoce some limits?
6 400 [ ] rg_ssh_host/rg_git_host must be set also in admin web page. [ ] rg_ssh_host/rg_git_host must be set also in admin web page.
7 401 [ ] When a file is empty, show it in a special way to not be tempted to click [ ] When a file is empty, show it in a special way to not be tempted to click
8 402 on it. on it.
9 [ ] LDAP
10 http://mageconfig.blogspot.ro/2014/06/configure-gitgerrit-with-open-ldap-for.html
11 add groups support
12 403 [ ] hostname problems: [ ] hostname problems:
13 404 We may want to add a new state (hostname_real) which will be set by We may want to add a new state (hostname_real) which will be set by
14 405 admin and will have precedence over 'hostname', which is only admin and will have precedence over 'hostname', which is only
15 406 guessed by first access. If 'hostname_real' is not set, add a warning guessed by first access. If 'hostname_real' is not set, add a warning
16 407 on all pages for admin user to set the correct hostname. on all pages for admin user to set the correct hostname.
17 [ ] compare: add number of lines of the project.
18 408 [ ] For repo stats, add also the number of lines. [ ] For repo stats, add also the number of lines.
19 409 [ ] Add a minimum password length and enforce it everywhere. [ ] Add a minimum password length and enforce it everywhere.
20 410 [ ] Never redirect if the Host:'s port is different from SERVER_PORT. [ ] Never redirect if the Host:'s port is different from SERVER_PORT.
21 411 (see docker with redirects) (see docker with redirects)
22 [ ] Add also "normal" we page (without virtualhost)
412 [ ] Add also "normal" web page (without virtualhost)
23 413 to be able to start with the current server? to be able to start with the current server?
24 414 [ ] For repo stats, we may want to use --all or --branches. [ ] For repo stats, we may want to use --all or --branches.
25 415 [ ] When showing a commit, Create links for "Parents"/"Tree". Probably others. [ ] When showing a commit, Create links for "Parents"/"Tree". Probably others.
 
35 425 [ ] Add AGPL logo to main web page? [ ] Add AGPL logo to main web page?
36 426 [ ] Add 'depends/number' label to mark some bugs as a dependency on another. [ ] Add 'depends/number' label to mark some bugs as a dependency on another.
37 427 What about duplicates? Confidential? What about duplicates? Confidential?
38 [ ] We do no track of the visitors. Also in git announce?
428 [ ] We do no track the visitors. Also in git announce?
39 429 [ ] Use 'restrict' when generating authorized_keys file. [ ] Use 'restrict' when generating authorized_keys file.
40 430 [ ] In report, report also the space used and a top 5? [ ] In report, report also the space used and a top 5?
41 431 [ ] At login time to destroy all forgot password pending tokens? [ ] At login time to destroy all forgot password pending tokens?
 
123 513 Maybe replace "History" with "Log" and "Tree" and make the Maybe replace "History" with "Log" and "Tree" and make the
124 514 select of the branch/tag as a select. select of the branch/tag as a select.
125 515 This is to not have another menu line. Is overkill. This is to not have another menu line. Is overkill.
126 [ ] Document GIT_TRACE=1 in the hints?
127 516 [ ] If a repo is empty, should I show "Tree" menu?! [ ] If a repo is empty, should I show "Tree" menu?!
128 517 Or at least, do not show an error! Or at least, do not show an error!
129 518 [ ] Why do I not block the receiving of the commits in 'pre-receive' hook?! [ ] Why do I not block the receiving of the commits in 'pre-receive' hook?!
 
145 534 [ ] html5: new types: http://html5doctor.com/html5-forms-input-types/ [ ] html5: new types: http://html5doctor.com/html5-forms-input-types/
146 535 [ ] WebAssembly: run rocketgit in a browser! [ ] WebAssembly: run rocketgit in a browser!
147 536 [ ] Rate limit rg.com (both connlimit and x) [ ] Rate limit rg.com (both connlimit and x)
148 [ ] ETag must not contain the inode (per vhost)
149 Apache goes with a sane default.
150 537 [ ] postgres: activate log_temp_files and log_lock_waits [ ] postgres: activate log_temp_files and log_lock_waits
151 538 [ ] Limit the size of files at commit (in the rights section) [ ] Limit the size of files at commit (in the rights section)
152 539 [ ] Investigate X-Content-Type-Options: "nosniff" [ ] Investigate X-Content-Type-Options: "nosniff"
 
173 560 [ ] https://liberapay.com/ [ ] https://liberapay.com/
174 561 [ ] https://gratipay.com/ [ ] https://gratipay.com/
175 562 [ ] https://www.bountysource.com/ [ ] https://www.bountysource.com/
176 [ ] https://www.bountysource.com/
177 563 [ ] http://breachattack.com/ [ ] http://breachattack.com/
178 564 Investigate the solution to sign[/encrypt] secrets and regenerate them Investigate the solution to sign[/encrypt] secrets and regenerate them
179 565 also to not store them in the database! I think the problem was the also to not store them in the database! I think the problem was the
 
213 599 [ ] For API keys (maybe others), "Last IP" may be the IP who added the key. [ ] For API keys (maybe others), "Last IP" may be the IP who added the key.
214 600 Or add an "Upload IP" field. Or add an "Upload IP" field.
215 601 [ ] Add NoNewPrivileges to rocketgit-fpm service? [ ] Add NoNewPrivileges to rocketgit-fpm service?
216 [ ] When I start the virtual machine, can I connect to console tu run the build
602 [ ] When I start the virtual machine, can I connect to console to run the build
217 603 script instead connecting by other means? To not have to modify script instead connecting by other means? To not have to modify
218 604 the image... the image...
219 [ ] Resize root partition to gain space and resize after boot.
220 605 [ ] Add instructions to resize the base image: [ ] Add instructions to resize the base image:
221 606 qemu-img resize Fedora-$TYPE-armhfp-25-1.3-sda.raw +10G qemu-img resize Fedora-$TYPE-armhfp-25-1.3-sda.raw +10G
222 607 Do not forget about the filesystem! Do not forget about the filesystem!
 
226 611 Add hints on how to do it. Add hints on how to do it.
227 612 [ ] LOW: Generate an internal CA, allow clients to download certificates [ ] LOW: Generate an internal CA, allow clients to download certificates
228 613 generated by this CA and verify them, to be able to act like ssh. generated by this CA and verify them, to be able to act like ssh.
614 [ ] LOW: act as a CA and allow users to download certificates so we can use
615 http as ssh?
229 616 [ ] Low: add CURLOPT_PINNEDPUBLICKEY for webhooks. [ ] Low: add CURLOPT_PINNEDPUBLICKEY for webhooks.
230 617 [ ] Add login token for http authentication! [ ] Add login token for http authentication!
231 618 [ ] Make sure ETag is activated. [ ] Make sure ETag is activated.
232 619 [ ] Add a hint on how to delete all files in a repository. [ ] Add a hint on how to delete all files in a repository.
233 620 [ ] patreon.com? [ ] patreon.com?
234 621 [ ] Add U2F support (see U2F Zero for free software/hardware) [ ] Add U2F support (see U2F Zero for free software/hardware)
235 [ ] LOW: act as a CA and allow users to download certificates so wwe can use
236 http as ssh?
237 622 [ ] wh: add possibility to add public variables (values is public) or [ ] wh: add possibility to add public variables (values is public) or
238 623 private variables (value cannot be retrieved) which will be provided private variables (value cannot be retrieved) which will be provided
239 624 inside hook. How it applies to CI? inside hook. How it applies to CI?
 
243 628 Ah, it is the owner! Ah, it is the owner!
244 629 [ ] LOW: Allow build image to be persistent. [ ] LOW: Allow build image to be persistent.
245 630 [ ] Deleting an account will not delete all stuff related (user_remove) [ ] Deleting an account will not delete all stuff related (user_remove)
246 [ ] add to rg somrthing like: https://letsencrypt.org/become-a-sponsor/
631 [ ] add to rg something like: https://letsencrypt.org/become-a-sponsor/
247 632 [ ] wh: add support for OpenWhisk, similar with Amazon's Lambda [ ] wh: add support for OpenWhisk, similar with Amazon's Lambda
248 633 [ ] On contributions page, as a way to help: recommend crowdfunding organzations. [ ] On contributions page, as a way to help: recommend crowdfunding organzations.
249 634 [ ] SSH: the ratelimit may block some users? [ ] SSH: the ratelimit may block some users?
 
272 657 [ ] test: do a test for rg_authorize command: upload a key and check by fp [ ] test: do a test for rg_authorize command: upload a key and check by fp
273 658 [ ] test: add one for SSH AuthorizedKeysCommand [ ] test: add one for SSH AuthorizedKeysCommand
274 659 [ ] LOW: add fuzzers for checking code. [ ] LOW: add fuzzers for checking code.
275 [ ] Put password above e-mail, maybe this will fix the problem with user/pass
276 caching.
277 [ ] Use skipfish /w3af/etc. for security scanning
660 [ ] Use skipfish/w3af/etc. for security scanning
278 661 [ ] LOW: investigate https://aws.amazon.com/codepipeline/ [ ] LOW: investigate https://aws.amazon.com/codepipeline/
279 662 [ ] wh: start an ec2 machine [ ] wh: start an ec2 machine
280 663 [ ] Discover: do not show repos which have no commit and no bug? [ ] Discover: do not show repos which have no commit and no bug?
281 [ ] apache: configure it to not stat every path component!
664 [ ] web server: configure it to not stat every path component!
282 665 [ ] First page: link to the Changelog? [ ] First page: link to the Changelog?
283 666 [ ] Compare: supported distributions [ ] Compare: supported distributions
284 667 [ ] What happends when an environment is not available anymore? [ ] What happends when an environment is not available anymore?
 
316 699 [ ] Debian: on reconfigure - add admin account? [ ] Debian: on reconfigure - add admin account?
317 700 [ ] Investivate gc.*, repack.* etc. configuration. [ ] Investivate gc.*, repack.* etc. configuration.
318 701 [ ] Use .mailmap when building stats? [ ] Use .mailmap when building stats?
319 [ ] Before start a builing, check if it was already built.
702 [ ] Before start a build, check if it was already built.
320 703 Think about a fast forward. Think about a fast forward.
321 704 [ ] API: When loading info about a user, do we need to show the e-mail? [ ] API: When loading info about a user, do we need to show the e-mail?
322 705 [ ] API: Seems I get: [ ] API: Seems I get:
 
359 742 [ ] Use 'guestfish --ro -a a.img -i'. What for? [ ] Use 'guestfish --ro -a a.img -i'. What for?
360 743 [ ] Add 'X-Content-Type-Options: nosniff' for raw responses. [ ] Add 'X-Content-Type-Options: nosniff' for raw responses.
361 744 [ ] Check 'X-XSS-Protection: 1; mode=block' [ ] Check 'X-XSS-Protection: 1; mode=block'
362 [ ] Better explain why world needs another git hosting repo.
745 [ ] Better explain why world needs another git hosting software.
363 746 [ ] Features: I did not explain what Affero means! Only GPL. [ ] Features: I did not explain what Affero means! Only GPL.
364 747 [ ] fpm: provide a classic startup file. [ ] fpm: provide a classic startup file.
365 748 [ ] Some errors are like: 'cannot insert/update'. Are not very helpful! [ ] Some errors are like: 'cannot insert/update'. Are not very helpful!
 
... ... to add a worker? Also, no hint is presented.
373 756 I do not think so... Should we have a write ahead log: I do not think so... Should we have a write ahead log:
374 757 something like we inform the cache that we need to clean an entry something like we inform the cache that we need to clean an entry
375 758 it the connection is broken. it the connection is broken.
376 [ ] UTF8 with the databse, please check.
377 [ ] main page: add a new way to ear money: add sponsort, directly in the source
759 [ ] UTF8 with the database, please check.
760 [ ] main page: add a new way to earn money: add sponsors, directly in the source
378 761 to be shown on every deployed rocketgit instalation. to be shown on every deployed rocketgit instalation.
379 762 We can use bidding for the order. We can use bidding for the order.
380 763 [ ] Investigate socket activation for fpm? Cache? Events? [ ] Investigate socket activation for fpm? Cache? Events?
 
... ... to add a worker? Also, no hint is presented.
515 898 How it will work?! By default, all rights. How it will work?! By default, all rights.
516 899 Use case: allow a key only to push on some repos (regex) Use case: allow a key only to push on some repos (regex)
517 900 Use case: allow a key to only access repo APIs. Use case: allow a key to only access repo APIs.
518 [ ] Scan SSH/API keys and notify user whey were used too long ago, and ask
901 [ ] Scan SSH/API keys and notify user when they were used too long ago, and ask
519 902 the user to remove them? the user to remove them?
520 903 [ ] From time to time, regenerate the passwords with other salt to protect [ ] From time to time, regenerate the passwords with other salt to protect
521 904 against stolen db and brute force attacks. against stolen db and brute force attacks.
 
... ... to add a worker? Also, no hint is presented.
527 910 logs. logs.
528 911 [ ] Add an API layer to be able to use other git hosting scripts to connect to me [ ] Add an API layer to be able to use other git hosting scripts to connect to me
529 912 [ ] Sign some contract with Nitrokey.com to provide keys to the users. [ ] Sign some contract with Nitrokey.com to provide keys to the users.
530 [ ] build: allow user to specify some packages to be installed first?
531 913 [ ] Destroy storage for 'build' machines [ ] Destroy storage for 'build' machines
532 914 [ ] Add a new right: "allow pushes only if they are signed". [ ] Add a new right: "allow pushes only if they are signed".
533 As with ss keys, a user may want to add public gpg keys to a list
915 As with ssh keys, a user may want to add public gpg keys to a list
534 916 that is allowed to push. Take care: you can sign tags but also that is allowed to push. Take care: you can sign tags but also
535 917 commits. commits.
536 918 [ ] Slack: push also the commit message. [ ] Slack: push also the commit message.
 
... ... to add a worker? Also, no hint is presented.
648 1030 [ ] LOW: mr: notify the owner of the pull request (if not anonymous)? [ ] LOW: mr: notify the owner of the pull request (if not anonymous)?
649 1031 [ ] LOW: when destroying a repo, destroy the cache by path (git caches by path) [ ] LOW: when destroying a repo, destroy the cache by path (git caches by path)
650 1032 [ ] LOW: /usr/share/rocketgit/root/themes/default//usr/share/rocketgit/root/themes/default/hints/list/header.html [ ] LOW: /usr/share/rocketgit/root/themes/default//usr/share/rocketgit/root/themes/default/hints/list/header.html
651 [ ] LOW: mr: private pull requests?
652 [ ] LOW: mr: get rid of namespaces?
1033 [ ] LOW: mr: get rid of namespaces? overlayfs?
653 1034 [ ] LOW: mr: add possibility to reject a pull request. [ ] LOW: mr: add possibility to reject a pull request.
654 1035 [ ] LOW: mr: add the right to reject pull requests. [ ] LOW: mr: add the right to reject pull requests.
655 1036 [ ] LOW: mr: allow adding comments for pull requests. [ ] LOW: mr: allow adding comments for pull requests.
 
... ... to add a worker? Also, no hint is presented.
657 1038 [ ] LOW: mr: allow the anonymous users to delete a pull request by providing [ ] LOW: mr: allow the anonymous users to delete a pull request by providing
658 1039 a link. a link.
659 1040 [ ] LOW: mr: allow the owner to remove a pull request. [ ] LOW: mr: allow the owner to remove a pull request.
660 [ ] LOW: mr: Use rg_git_request_pull to generate a pull request from a onw repo.
1041 [ ] LOW: mr: Use rg_git_request_pull to generate a pull request from an own repo.
661 1042 Example: git request-pull master~4 git://localhost/user/catab/testpull Example: git request-pull master~4 git://localhost/user/catab/testpull
662 1043 We must present a list of commits, so the user can choose 'start' and We must present a list of commits, so the user can choose 'start' and
663 1044 'end'. 'end'.
 
... ... to add a worker? Also, no hint is presented.
678 1059 [ ] LOW: mr: commits must be isolated in div islands with some background [ ] LOW: mr: commits must be isolated in div islands with some background
679 1060 [ ] LOW: mr: maybe files should be listen on the right of the commit info? [ ] LOW: mr: maybe files should be listen on the right of the commit info?
680 1061 [ ] LOW: mr: Commits must be indented somehow. [ ] LOW: mr: Commits must be indented somehow.
681 [ ] LOW: mr: between diff and "Commit xxx" the is no space!
1062 [ ] LOW: mr: between diff and "Commit xxx" there is no space!
682 1063 [ ] LOW: In log/line.html, subject should also be a link to the commit [ ] LOW: In log/line.html, subject should also be a link to the commit
683 1064 [ ] LOW: mr: allow user to resolve conflicts online? [ ] LOW: mr: allow user to resolve conflicts online?
684 1065 [ ] LOW: mr: error messages must still show the merge information. [ ] LOW: mr: error messages must still show the merge information.
 
... ... them after processing is done.
2020 2401 [ ] Check double slashes in URLs. [ ] Check double slashes in URLs.
2021 2402 [ ] Automatically create user on anonymous push? [ ] Automatically create user on anonymous push?
2022 2403 [ ] I am not sure I can reload xinetd and httpd from spec file [ ] I am not sure I can reload xinetd and httpd from spec file
2023 [ ] Check SELinux context on /var/lib/rocketgit
2024 2404 [ ] admin: "Lock all accounts" and "Reset password for all accounts and send mail". [ ] admin: "Lock all accounts" and "Reset password for all accounts and send mail".
2025 2405 [ ] Get memory statistics from /proc. [ ] Get memory statistics from /proc.
2026 2406 [ ] Add support for refs/notes/ pushes. [ ] Add support for refs/notes/ pushes.
 
... ... them after processing is done.
2028 2408 [ ] Ask password when doing any critical change of the account and send mail. [ ] Ask password when doing any critical change of the account and send mail.
2029 2409 [ ] Add a possibility (link shown in push message) to delete/update/etc. the [ ] Add a possibility (link shown in push message) to delete/update/etc. the
2030 2410 merge request. merge request.
2031 [ ] Allow a nonstandard port for web.
2032 2411 [ ] Put form error messages next to the label. [ ] Put form error messages next to the label.
2033 2412 [ ] favicon.ico is not in theme! Should we put it in HTML? [ ] favicon.ico is not in theme! Should we put it in HTML?
2034 2413 [ ] Create unit testing for all functions. [ ] Create unit testing for all functions.
2035 2414 [ ] Test error code for rg_sql_query. [ ] Test error code for rg_sql_query.
2036 2415 [ ] Log $ret['errmsg'] for rg_exec [ ] Log $ret['errmsg'] for rg_exec
2037 2416 [ ] Audit code to replace parts with rg_internal_error. [ ] Audit code to replace parts with rg_internal_error.
2038 [ ] Allow SSH keys per repository (only)?
2417 [ ] Allow SSH keys per repository (only)? regex?
2039 2418 [ ] Allow remote 'gc' of a repo, besides an automatic one. [ ] Allow remote 'gc' of a repo, besides an automatic one.
2040 2419 [ ] Take care of caching of passwords. Maybe allow a purge of a file from browser? [ ] Take care of caching of passwords. Maybe allow a purge of a file from browser?
2041 2420 [ ] "Lock" button to temporary block access to repository. [ ] "Lock" button to temporary block access to repository.
2042 2421 Only owner will have access. Only owner will have access.
2043 2422 We may add also a text that will be output to clients. We may add also a text that will be output to clients.
2423 Add to 'compare'.
2044 2424 [ ] List changes introduced by a merge: git diff-tree --always [--cc] -m -p f7d5b5770f4c6b5a124dad6358bed310d56bf909 [ ] List changes introduced by a merge: git diff-tree --always [--cc] -m -p f7d5b5770f4c6b5a124dad6358bed310d56bf909
2045 2425 [ ] Check pack-protocol.txt! [ ] Check pack-protocol.txt!
2046 2426 [ ] When push is executed with success, show a nice message from RocketGit. [ ] When push is executed with success, show a nice message from RocketGit.
 
... ... them after processing is done.
2083 2463 hook? Or update is the best place? hook? Or update is the best place?
2084 2464 [ ] Limit number of commits per push. [ ] Limit number of commits per push.
2085 2465 [ ] RSS [ ] RSS
2086 [ ] Smart HTTP transport
2087 2466 [ ] Move forget pass token into users table. [ ] Move forget pass token into users table.
2088 2467 [ ] Audit all error messages to not propagate useful info to an attacker. [ ] Audit all error messages to not propagate useful info to an attacker.
2089 2468 Split in two error messages: one for logs and one for user. Split in two error messages: one for logs and one for user.
 
... ... them after processing is done.
2097 2476 [ ] Check SELinux MLS [ ] Check SELinux MLS
2098 2477 [ ] Deal with empty repositories (rg_git_ls_tree etc.). [ ] Deal with empty repositories (rg_git_ls_tree etc.).
2099 2478 [ ] Show age of an user/org/repo. Example: 1 year, 3 months, 4 days. [ ] Show age of an user/org/repo. Example: 1 year, 3 months, 4 days.
2100 [ ] The rewrite engine should pass a single op for user and for org, but with
2101 para org=0 or 1.
2102 This is to have the same page for both types of users.
2103 2479 [ ] From: http://lwn.net/Articles/460376/ [ ] From: http://lwn.net/Articles/460376/
2104 2480 I can confirm that shortcomings with Gitorious' ACL systems were I can confirm that shortcomings with Gitorious' ACL systems were
2105 2481 definitely one of the reasons we ended up deciding against it -- definitely one of the reasons we ended up deciding against it --
File compare.csv changed (mode: 100644) (index 548f8c1..19c57cf)
21 21 "Web Hooks - provide client certs","Yes","No","No","n/a","?","No" "Web Hooks - provide client certs","Yes","No","No","n/a","?","No"
22 22 "Web Hooks - authenticate server (CA cert)","Yes","No","No","n/a","?","No" "Web Hooks - authenticate server (CA cert)","Yes","No","No","n/a","?","No"
23 23 "OpenSSH AuthorizedKeysCommand","Yes","Yes","Yes","?","No","?" "OpenSSH AuthorizedKeysCommand","Yes","Yes","Yes","?","No","?"
24 "OpenSSH filter by key type and bits {Can it disable the keys based on types and number of bits?}","Yes","No","?","No","No","Yes"
24 "OpenSSH filter by key type and bits {Can it disable the keys based on types and number of bits?}","Yes","Yes","?","No","No","Yes"
25 25 "Detailed info about the SSH keys {Can it show: type, number of bits, when it was uploaded, when it was first/last used, how many times was used and last command?}","Yes","No","?","No","No","?" "Detailed info about the SSH keys {Can it show: type, number of bits, when it was uploaded, when it was first/last used, how many times was used and last command?}","Yes","No","?","No","No","?"
26 26 "LDAP user authentication","No","Yes","?","No","No","Yes" "LDAP user authentication","No","Yes","?","No","No","Yes"
27 "LDAP groups","No","?","?","?","?","?"
27 "LDAP groups","No","Yes","?","?","?","?"
28 28 "PAM user authentication","No","?","?","?","?","Yes" "PAM user authentication","No","?","?","?","?","Yes"
29 29 "Git LFS","No","Yes","Yes","Yes","No","No" "Git LFS","No","Yes","Yes","Yes","No","No"
30 30 "Lock repo with a message","Yes","?","?","?","?","?" "Lock repo with a message","Yes","?","?","?","?","?"
 
42 42 "KVM image available?","Yes","?","?","not needed/#0f0","?","?" "KVM image available?","Yes","?","?","not needed/#0f0","?","?"
43 43 "VirtualBox image available?","Yes","?","?","not needed/#0f0","?","?" "VirtualBox image available?","Yes","?","?","not needed/#0f0","?","?"
44 44 "VMWare image available?","Yes","?","?","not needed/#0f0","?","?" "VMWare image available?","Yes","?","?","not needed/#0f0","?","?"
45 "Docker container available?","Yes","?","?","?","?","?"
45 "Docker container available?","Yes","Yes","?","?","?","?"
46 46 ,,,,,, ,,,,,,
47 47 "[Details]",,,,,, "[Details]",,,,,,
48 48 "Language","PHP","Ruby+Perl","Ruby","Perl","Python","Go" "Language","PHP","Ruby+Perl","Ruby","Perl","Python","Go"
File inc/admin.inc.php changed (mode: 100644) (index de14172..9fce1b3)
... ... function rg_init($db, $rg)
223 223 $rg['init']['pass2'] = rg_var_str('init::pass2'); $rg['init']['pass2'] = rg_var_str('init::pass2');
224 224 $rg['init']['session_time'] = rg_var_uint('init::session_time'); $rg['init']['session_time'] = rg_var_uint('init::session_time');
225 225 $rg['init']['confirmed'] = time(); /* = no need to confirm */ $rg['init']['confirmed'] = time(); /* = no need to confirm */
226 $rg['init']['ask_for_email_confirmation'] = 0;
227 226
228 227 if (!rg_valid_referer()) { if (!rg_valid_referer()) {
229 228 $errmsg[] = "invalid referer; try again"; $errmsg[] = "invalid referer; try again";
File inc/admin/admin.php changed (mode: 100644) (index bdad503..703f2b5)
... ... case 'users': // users
30 30 $_admin_body = $_admin_users; $_admin_body = $_admin_users;
31 31 break; break;
32 32
33 case 'repos': // repos
33 case 'repos':
34 34 include($INC . "/admin/repos/repos.php"); include($INC . "/admin/repos/repos.php");
35 35 $_admin_body = $_admin_repos; $_admin_body = $_admin_repos;
36 36 break; break;
37 37
38 case 'ldap':
39 $_admin_body = rg_ldap_high_level($db, $rg, $paras);
40 break;
41
38 42 case 'workers': case 'workers':
39 43 $_admin_body = rg_worker_high_level($db, $rg, $paras); $_admin_body = rg_worker_high_level($db, $rg, $paras);
40 44 break; break;
File inc/admin/plans/plans.php changed (mode: 100644) (index c3c8a87..3a75234)
... ... $_op = empty($paras) ? "list" : array_shift($paras);
7 7 rg_log("DEBUG: _op=$_op sparas=" . rg_array2string($paras)); rg_log("DEBUG: _op=$_op sparas=" . rg_array2string($paras));
8 8
9 9 $rg['admin_plans_menu'][$_op] = 1; $rg['admin_plans_menu'][$_op] = 1;
10 $rg['HTML:menu_level2'] = rg_template("admin/plans/menu.html", $rg, TRUE /* xss */);
10 $rg['HTML:menu_level2'] = rg_template("admin/plans/menu.html", $rg, TRUE /*xss*/);
11 11
12 12 switch ($_op) { switch ($_op) {
13 13 case 'list': // list case 'list': // list
File inc/api.inc.php changed (mode: 100644) (index af3f3f5..ee5a63b)
... ... function rg_api($db, $a)
17 17 rg_prof_start('api'); rg_prof_start('api');
18 18 rg_log_enter('api: a=' . rg_array2string($a)); rg_log_enter('api: a=' . rg_array2string($a));
19 19
20 $ret = array();
21 20 while (1) { while (1) {
22 21 $a['cui'] = rg_user_info($db, $a['connect_uid'], '', ''); $a['cui'] = rg_user_info($db, $a['connect_uid'], '', '');
23 22 if ($a['cui']['exists'] != 1) { if ($a['cui']['exists'] != 1) {
File inc/builder.inc.php changed (mode: 100644) (index b82fe3a..e4949cb)
... ... function rg_builder_load_jobs($db)
51 51 */ */
52 52 function rg_builder_add($db, $repo_id, $d) function rg_builder_add($db, $repo_id, $d)
53 53 { {
54 $ret = array('ok' => 0);
55
56 54 rg_log_ml('builder_add: ' . print_r($d, TRUE)); rg_log_ml('builder_add: ' . print_r($d, TRUE));
55
56 $ret = array('ok' => 0);
57 57 while (1) { while (1) {
58 58 $params = array( $params = array(
59 59 'repo_id' => $repo_id, 'repo_id' => $repo_id,
 
... ... function rg_builder_add($db, $repo_id, $d)
68 68 . ' VALUES (@@repo_id@@, @@prio@@, @@itime@@' . ' VALUES (@@repo_id@@, @@prio@@, @@itime@@'
69 69 . ', @@request@@, @@done@@, @@status@@)'; . ', @@request@@, @@done@@, @@status@@)';
70 70 $res = rg_sql_query_params($db, $sql, $params); $res = rg_sql_query_params($db, $sql, $params);
71 if ($res === FALSE)
71 if ($res === FALSE) {
72 $ret['errmsg'] = 'cannot add job';
72 73 break; break;
74 }
75 rg_sql_free_result($res);
73 76
74 77 // TODO: notify build system to not poll? // TODO: notify build system to not poll?
75 78 $ret['ok'] = 1; $ret['ok'] = 1;
File inc/events.inc.php changed (mode: 100644) (index 6859bd8..da4a3d4)
... ... function rg_event_process_queue($db, &$notify_list)
279 279 } }
280 280
281 281 $res2 = rg_sql_query_params($db, $sql, $params); $res2 = rg_sql_query_params($db, $sql, $params);
282 if ($res2 === FALSE) {
283 rg_event_set_error('internal error');
284 break;
285 }
282 286 rg_sql_free_result($res2); rg_sql_free_result($res2);
283 287 } }
284 288 rg_sql_free_result($res); rg_sql_free_result($res);
File inc/git.inc.php changed (mode: 100644) (index 0d076ba..a0330ff)
... ... function rg_git_diff2array($diff, &$out)
722 722 $file = $a['file']; $file = $a['file'];
723 723 if (!isset($out[$file])) { if (!isset($out[$file])) {
724 724 rg_git_set_error('internal error'); rg_git_set_error('internal error');
725 rg_internal_error('we have a diff for a non-existing file');
725 rg_internal_error('we have a diff for a'
726 . ' non-existing file (' . $file . ')');
726 727 $ret = FALSE; $ret = FALSE;
727 728 break; break;
728 729 } }
 
... ... function rg_git_log_simple($repo_path, $max, $from, $to, $also_patch, $files,
1053 1054 //rg_log('DEBUG: File [' . $f . '] ' //rg_log('DEBUG: File [' . $f . '] '
1054 1055 // . $changes . ' changes'); // . $changes . ' changes');
1055 1056 $y['files'][$f]['oversize_diff'] = $y['files'][$f]['oversize_diff'] =
1056 $changes > $patch_limit ? 1 : 0;
1057 ($also_patch && ($changes > $patch_limit)) ? 1 : 0;
1057 1058
1058 1059 // Add to total // Add to total
1059 1060 $y['vars']['lines_add'] += $y['files'][$f]['lines_add']; $y['vars']['lines_add'] += $y['files'][$f]['lines_add'];
 
... ... function rg_git_log_detect_big_diff($stat, $from)
1183 1184 //rg_log_ml('DEBUG final (after detect big diff): ' . print_r($ret, TRUE)); //rg_log_ml('DEBUG final (after detect big diff): ' . print_r($ret, TRUE));
1184 1185
1185 1186 // No need to parse the array // No need to parse the array
1186 if ($at_least_one_bad === FALSE)
1187 if ($at_least_one_bad === FALSE) {
1188 rg_log('DEBUG: No big diff detected.');
1187 1189 $ret = array(); $ret = array();
1190 }
1188 1191
1192 rg_log('DEBUG: Big diff detected.');
1189 1193 rg_log_exit(); rg_log_exit();
1190 1194 return $ret; return $ret;
1191 1195 } }
 
... ... function rg_git_log($repo_path, $max, $from, $to, $also_patch, $patch_limit)
1217 1221 break; break;
1218 1222 } }
1219 1223
1224 rg_log_ml('DEBUG: stat: ' . print_r($stat, TRUE));
1225
1220 1226 $r = rg_git_log_detect_big_diff($stat, $from); $r = rg_git_log_detect_big_diff($stat, $from);
1221 1227 if (empty($r)) { // = no big diff if (empty($r)) { // = no big diff
1222 1228 $good_files = array(); // = all $good_files = array(); // = all
 
... ... function rg_git_log($repo_path, $max, $from, $to, $also_patch, $patch_limit)
1226 1232 } }
1227 1233
1228 1234 foreach ($r as $i) { foreach ($r as $i) {
1229 //rg_log_ml('DEBUG: Generating log for ' . print_r($i, TRUE));
1235 rg_log_ml('DEBUG: Generating log for ' . print_r($i, TRUE));
1230 1236
1231 1237 if (strcmp($i['type'], 'good') == 0) if (strcmp($i['type'], 'good') == 0)
1232 1238 $_files = array(); $_files = array();
1233 else
1239 else if (!empty($i['good_files']))
1234 1240 $_files = $i['good_files']; $_files = $i['good_files'];
1241 else
1242 continue;
1235 1243
1236 1244 $x = rg_git_log_simple($repo_path, $max, $x = rg_git_log_simple($repo_path, $max,
1237 1245 $i['from'], $i['to'], $also_patch, $_files, $i['from'], $i['to'], $also_patch, $_files,
 
... ... function rg_git_log($repo_path, $max, $from, $to, $also_patch, $patch_limit)
1260 1268 break; break;
1261 1269 } }
1262 1270
1263 rg_log_ml('FINAL: ' . print_r($ret, TRUE));
1271 //rg_log_ml('DEBUG FINAL: ' . print_r($ret, TRUE));
1264 1272
1265 1273 rg_log_exit(); rg_log_exit();
1266 1274 rg_prof_end('git_log'); rg_prof_end('git_log');
File inc/ldap.inc.php added (mode: 100644) (index 0000000..39aa7ed)
1 <?php
2 require_once($INC . '/sql.inc.php');
3 require_once($INC . '/state.inc.php');
4 require_once($INC . '/prof.inc.php');
5 require_once($INC . '/cache.inc.php');
6 require_once($INC . '/plan.inc.php');
7 require_once($INC . '/ldap_core.inc.php');
8 require_once($INC . '/ldap_sync.inc.php');
9
10
11 $rg_ldap_error = '';
12
13 function rg_ldap_set_error($str)
14 {
15 global $rg_ldap_error;
16 $rg_ldap_error = $str;
17 rg_log($str);
18 }
19
20 function rg_ldap_error()
21 {
22 global $rg_ldap_error;
23 return $rg_ldap_error;
24 }
25
26 /*
27 * Some cosmetics applied to a LDAP server (one row)
28 */
29 function rg_ldap_cosmetic_row($db, &$row)
30 {
31 if (isset($row['itime']))
32 $row['itime_nice'] = gmdate('Y-m-d H:i', $row['itime']);
33
34 $pi = rg_plan_info($db, $row['plan_id']);
35 if ($pi['exists'] == 1)
36 $row['plan'] = $pi['name'];
37 else
38 $row['plan'] = 'Error!';
39 }
40
41 /*
42 * Some cosmetics applied to a LDAP server (array)
43 */
44 function rg_ldap_cosmetic($db, &$a)
45 {
46 foreach ($a as $k => &$i)
47 rg_ldap_cosmetic_row($db, $i);
48 }
49
50 /*
51 * Sorting the LDAP servers
52 */
53 function rg_ldap_sort_helper($a, $b)
54 {
55 if ($a['prio'] < $b['prio'])
56 return -1;
57
58 if ($a['prio'] > $b['prio'])
59 return 1;
60
61 return strcmp($a['name'], $b['name']);
62 }
63
64 /*
65 * Returns a list of LDAP servers
66 */
67 function rg_ldap_list($db)
68 {
69 rg_prof_start('ldap_list');
70 rg_log_enter('ldap_list');
71
72 $ret = array('ok' => 0, 'list' => array());
73 while (1) {
74 $key = 'ldap';
75 $r = rg_cache_get($key);
76 if (($r !== FALSE) && isset($r['LIST_LOADED'])) {
77 $ret['list'] = $r['list'];
78 $ret['ok'] = 1;
79 break;
80 }
81
82 $params = array();
83 $sql = 'SELECT * FROM ldap_servers ORDER BY prio, name';
84 $res = rg_sql_query_params($db, $sql, $params);
85 if ($res === FALSE) {
86 rg_ldap_set_error('cannot load data');
87 break;
88 }
89
90 while (($row = rg_sql_fetch_array($res))) {
91 $id = $row['id'];
92 $ret['list'][$id] = $row;
93 }
94 rg_sql_free_result($res);
95
96 $a = array('LIST_LOADED' => 1, 'list' => $ret['list']);
97 rg_cache_merge($key, $a, RG_SOCKET_NO_WAIT);
98 $ret['ok'] = 1;
99 break;
100 }
101 uasort($ret['list'], 'rg_ldap_sort_helper');
102
103 rg_log_exit();
104 rg_prof_end('ldap_list');
105 return $ret;
106 }
107
108 /*
109 * Adds/edits a ldap_server
110 */
111 function rg_ldap_add($db, $who, $data)
112 {
113 rg_prof_start('ldap_add');
114 rg_log_enter('ldap_add');
115
116 $ret = array('ok' => 0);
117 while (1) {
118 $data['who'] = $who;
119 $data['itime'] = time();
120 $params = $data;
121
122 if ($data['id'] == 0) {
123 $sql = 'INSERT INTO ldap_servers (itime, who, name'
124 . ', url, bind_dn, bind_pass, user_base'
125 . ', uid_attr, filter, group_base, group_attr'
126 . ', group_filter, admin_group, ca_cert'
127 . ', prio, session_time)'
128 . ' VALUES (@@itime@@, @@who@@, @@name@@'
129 . ', @@url@@, @@bind_dn@@, @@bind_pass@@'
130 . ', @@user_base@@, @@uid_attr@@, @@filter@@'
131 . ', @@group_base@@, @@group_attr@@'
132 . ', @@group_filter@@, @@admin_group@@'
133 . ', @@ca_cert@@, @@prio@@, @@session_time@@)'
134 . ' RETURNING id';
135 } else {
136 $sql = 'UPDATE ldap_servers'
137 . ' SET itime = @@itime@@'
138 . ', who = @@who@@'
139 . ', name = @@name@@'
140 . ', url = @@url@@'
141 . ', bind_dn = @@bind_dn@@'
142 . ', bind_pass = @@bind_pass@@'
143 . ', user_base = @@user_base@@'
144 . ', uid_attr = @@uid_attr@@'
145 . ', filter = @@filter@@'
146 . ', group_base = @@group_base@@'
147 . ', group_attr = @@group_attr@@'
148 . ', group_filter = @@group_filter@@'
149 . ', admin_group = @@admin_group@@'
150 . ', ca_cert = @@ca_cert@@'
151 . ', prio = @@prio@@'
152 . ', session_time = @@session_time@@'
153 . ' WHERE id = @@id@@';
154 }
155
156 $res = rg_sql_query_params($db, $sql, $params);
157 if ($res === FALSE) {
158 rg_ldap_set_error('cannot insert/update data');
159 break;
160 }
161 if ($data['id'] == 0)
162 $row = rg_sql_fetch_array($res);
163 rg_sql_free_result($res);
164
165 if ($data['id'] == 0)
166 $data['id'] = $row['id'];
167 $key = 'ldap' . '::' . 'list'
168 . '::' . $data['id'];
169 rg_cache_merge($key, $data, RG_SOCKET_NO_WAIT);
170
171 $ret['ok'] = 1;
172 break;
173 }
174
175 rg_log_exit();
176 rg_prof_end('ldap_add');
177 return $ret;
178 }
179
180 /*
181 * Removes a list of ldap_servers
182 */
183 function rg_ldap_remove($db, $list)
184 {
185 rg_prof_start('ldap_remove');
186 rg_log_enter('ldap_remove');
187
188 $ret = array('ok' => 0);
189 while (1) {
190 if (empty($list)) {
191 rg_ldap_set_error('you did not select anything');
192 break;
193 }
194
195 $my_list = array();
196 foreach ($list as $id => $junk)
197 $my_list[] = sprintf('%u', $id);
198
199 $params = array();
200 $sql_list = implode(', ', $my_list);
201
202 $sql = 'DELETE FROM ldap_cache'
203 . ' WHERE server_id IN (' . $sql_list . ')';
204 $res = rg_sql_query_params($db, $sql, $params);
205 if ($res === FALSE) {
206 rg_ldap_set_error('cannot remove data from db cache');
207 break;
208 }
209 rg_sql_free_result($res);
210
211 $sql = 'DELETE FROM ldap_servers'
212 . ' WHERE id IN (' . $sql_list . ')';
213 $res = rg_sql_query_params($db, $sql, $params);
214 if ($res === FALSE) {
215 rg_ldap_set_error('cannot remove server from db');
216 break;
217 }
218 rg_sql_free_result($res);
219
220 foreach ($my_list as $junk => $id) {
221 $key = 'ldap' . '::' . 'list' . '::' . $id;
222 rg_cache_unset($key, RG_SOCKET_NO_WAIT);
223 }
224
225 $ret['ok'] = 1;
226 break;
227 }
228
229 rg_log_exit();
230 rg_prof_end('ldap_remove');
231 return $ret;
232 }
233
234 /*
235 * Helper function for ldap_login
236 */
237 function rg_ldap_a_and_si_to_a_ui(&$ui, &$a, $si)
238 {
239 $a['username'] = $a['ldap_uid'];
240 $a['realname'] = $a['cn'] . ' (' . $a['gn'] . ' ' . $a['sn'] . ')';
241
242 $ui['session_time'] = $si['session_time'];
243 $ui['plan_id'] = $si['plan_id'];
244 $ui['realname'] = $a['realname'];
245 $ui['username'] = $a['username'];
246 $ui['email'] = $a['mail'];
247 $ui['pass'] = $a['password'];
248 $ui['pass2'] = $a['password'];
249
250 $ui['confirm_token'] = '';
251 $ui['confirmed'] = 1;
252 $ui['exists'] = 1;
253 $ui['deleted'] = 0;
254 $ui['suspended'] = 0;
255 }
256
257 /*
258 * Authentication function used by rg_user_login_by_user_pass
259 */
260 rg_register_login_function(
261 array(
262 'login' => 'rg_ldap_login',
263 'post_login' => 'rg_ldap_login_post'
264 )
265 );
266 function rg_ldap_login($db, $user, $pass, &$ui)
267 {
268 global $rg_session_time;
269
270 rg_log_enter('ldap_login');
271
272 $ret = array();
273 $ret['ok'] = 0;
274 $found = FALSE;
275 while (1) {
276 $sl = rg_ldap_list($db);
277 if ($sl['ok'] !== 1) {
278 $ret['errmsg'] = $sl['errmsg'];
279 break;
280 }
281
282 // First, we try to find the user in cache
283 // TODO: make the cache to expire
284 $r = rg_ldap_sync_get_cache($db, $user);
285 if ($r['ok'] === 1) {
286 foreach ($r['list'] as $a) {
287 rg_log_ml('DEBUG: cache: ' . print_r($a, TRUE));
288 // TODO: test if the entry is expired
289 // TODO: encrypt password!
290 if (strcmp($a['password'], $pass) != 0) {
291 rg_log('DEBUG: passwords do not match ['
292 . $a['password'] . '] [' . $pass . ']');
293 continue;
294 }
295
296 $server_id = $a['server_id'];
297 if (!isset($sl['list'][$server_id])) {
298 rg_internal_error('We found a stall'
299 . ' ldap server_id in cache!');
300 continue;
301 }
302
303 rg_log('DEBUG: Found a good cache entry!');
304 rg_ldap_a_and_si_to_a_ui($ui, $a,
305 $sl['list'][$server_id]);
306
307 if ($a['uid'] > 0)
308 $ui['uid'] = $a['uid'];
309
310 $ret['post'] = $a;
311 $ret['ok'] = 1;
312 break;
313 }
314 if ($ret['ok'] == 1)
315 break;
316 }
317
318 $euser = ldap_escape($user, NULL, LDAP_ESCAPE_FILTER);
319
320 foreach ($sl['list'] as $si) {
321 //rg_log_ml('ldap server info: ' . print_r($si, TRUE));
322
323 $r = rg_ldap_core_connect($si['url']);
324 if ($r['ok'] !== 1) {
325 rg_log('DEBUG: cannot connect: ' . $r['errmsg']);
326 $ret['errmsg'] = $r['errmsg'];
327 continue;
328 }
329 $con = $r['con'];
330 rg_log('DEBUG: connected to ' . $si['url']);
331
332 rg_log('DEBUG: binding as [' . $si['bind_dn'] . ']');
333 $r = rg_ldap_core_bind($con, $si['bind_dn'],
334 $si['bind_pass']);
335 if ($r['ok'] !== 1) {
336 rg_log('DEBUG: cannot bind: ' . $r['errmsg']);
337 $ret['errmsg'] = $r['errmsg'];
338 continue;
339 }
340 rg_log('DEBUG: bind1 ok!');
341
342 // TODO: should I validate uid field - injection?
343 $uid_attr = strtolower($si['uid_attr']);
344 $filter = '(|'
345 . '(mail=' . $euser . ')'
346 . '(cn=' . $euser . ')'
347 . '(' . $uid_attr . '=' . $euser . ')'
348 . ')';
349 if (!empty($si['filter']))
350 $filter = '(&' . $filter
351 . '(' . ldap_escape($si['filter'], NULL, LDAP_ESCAPE_FILTER) . '))';
352 rg_log('DEBUG: filter: ' . $filter);
353 rg_log('DEBUG: base=' . $si['user_base']);
354
355 $deref = LDAP_DEREF_NEVER; // TODO: this should be in $si
356 $attr = array('cn', 'mail', 'entryUUID', 'memberOf',
357 'mail', 'sn', 'givenName', 'objectClass',
358 'uid', 'shadowExpire', 'uidNumber', 'gidNumber',
359 $uid_attr);
360 $r = rg_ldap_core_search($con, $si['user_base'], $filter,
361 $attr, 0 /*attronly*/, 0 /*sizelimit*/,
362 0 /*timelimit*/, $deref);
363 if ($r['ok'] !== 1) {
364 rg_log('DEBUG: cannot search: ' . $r['errmsg']);
365 $ret['errmsg'] = $r['errmsg'];
366 continue;
367 }
368 if (empty($r['data']) || !isset($r['data'][0])) {
369 rg_log('DEBUG: cannot find data');
370 $ret['errmsg'] = 'user not found';
371 continue;
372 }
373
374 // Have to test here if we can bind with the user found
375 // We may have more users, but we will select the first one
376 $d = $r['data'][0];
377 rg_log('DEBUG: binding as [' . $d['dn'] . '] pass=' . $pass);
378 $r = rg_ldap_core_bind($con, $d['dn'], $pass);
379 if ($r['ok'] !== 1) {
380 rg_log('DEBUG: cannot bind: ' . $r['errmsg']);
381 $ret['errmsg'] = $r['errmsg'];
382 continue;
383 }
384 rg_log('DEBUG: bind2 ok!');
385
386 unset($ret['errmsg']);
387 $found = TRUE;
388 break;
389 }
390 if (!$found)
391 break;
392
393 rg_log_ml('DEBUG: got data from LDAP: d=' . print_r($d, TRUE));
394
395 // $a will be the $ret['post']
396 // It will be used to test if an update into 'users' is needed.
397 // Also, to insert into ldap_cache.
398 $a = array();
399 $a['cn'] = isset($d['cn'][0]) ? $d['cn'][0] : '';
400 $a['gn'] = isset($d['givenname'][0]) ? $d['givenname'][0] : '';
401 $a['sn'] = isset($d['sn'][0]) ? $d['sn'][0] : '';
402 $a['shadow_expire'] = isset($d['shadowexpire'][0]) ? $d['mail'][0] : '99999';
403 $uid_attr = strtolower($si['uid_attr']);
404 $a['ldap_uid'] = isset($d[$uid_attr][0]) ? $d[$uid_attr][0] : '';
405 $a['mail'] = isset($d['mail'][0]) ? $d['mail'][0] : '';
406 // TODO: really needed? I think not, we will use it in ldap_cache
407 //$a['uid_number'] = isset($d['uidnumber'][0]) ? $d['mail'][0] : '';
408 $a['password'] = $pass;
409 rg_log_ml('DEBUG: built a=' . print_r($a, TRUE));
410
411 rg_ldap_a_and_si_to_a_ui($ui, $a, $si);
412
413 // TODO: what to do when the admin changes the plan_id per server?
414 // I have to identify the users and change the plan.
415
416 $ui['is_admin'] = 0;
417 if (isset($d['memberof'])) {
418 for ($j = 0; $j < $d['memberof']['count']; $j++) {
419 //rg_log('DEBUG: comparing ' . $d['memberof'][$j] . ' with ' . $si['admin_group']);
420 // TODO: Do I have to escape `?
421 $r = @preg_match('`' . $si['admin_group'] . '`uD', $d['memberof'][$j]);
422 if ($r === 1) {
423 $ui['is_admin'] = 1;
424 break;
425 }
426 }
427 }
428
429 $ui['suspended'] = $a['shadow_expire'] <= time() / 24 / 3600 ? 1 : 0;
430 // TODO: With 99999 it will not compute right!
431 $ui['expire'] = gmmktime(0, 0, 0, 1, ($a['shadow_expire'] + 24 * 3600 - 1) / 24 / 3600, 1970) - 1;
432
433 $ui['ok'] = 1;
434
435 rg_log_ml('DEBUG: ui: ' . print_r($ui, TRUE));
436
437 // Prepare these for 'login_post' function, to update the cache.
438 $ret['post'] = $a;
439 $ret['post']['uid'] = 0;
440 $ret['post']['password'] = $pass;
441 $ret['post']['gid'] = isset($d['gidnumber'][0]) ? $d['gidnumber'][0] : 0;
442 $ret['post']['mail'] = $a['mail'];
443 $ret['post']['server_id'] = $si['id'];
444 $ret['post']['uuid'] = isset($d['entryuuid'][0]) ? $d['entryuuid'][0] : '';
445
446 $ret['ok'] = 1;
447 break;
448 }
449
450 rg_log_exit();
451 return $ret;
452 }
453
454 /*
455 * This is called from rg_user_login_by_user_pass.
456 * It will update the ldap_cache table.
457 * @post: it is the 'post' array member returned by rg_ldap_login
458 */
459 function rg_ldap_login_post($db, $uid, $post)
460 {
461 rg_log_enter('ldap_login_post');
462
463 rg_log_ml('DEBUG: uid=' . $uid);
464 rg_log_ml('DEBUG: post: ' . print_r($post, TRUE));
465
466 $ret = array('ok' => 0);
467 while (1) {
468 if ($post['uid'] != $uid) {
469 rg_log('DEBUG: we need to update ldap_cache.uid');
470 $post['uid'] = $uid;
471 $r = rg_ldap_sync_update_cache($db, $post);
472 if ($r['ok'] != 1) {
473 $ret['errmsg'] = $r['errmsg'];
474 break;
475 }
476 }
477
478 $ret['ok'] = 1;
479 break;
480 }
481
482 rg_log_exit();
483 return $ret;
484 }
485
486 /*
487 * High level function to list the LDAP servers
488 */
489 function rg_ldap_list_high_level($db, $rg, $paras)
490 {
491 rg_prof_start('ldap_list_high_level');
492 rg_log_enter('ldap_list_high_level');
493
494 $ret = '';
495
496 $errmsg = array();
497
498 $delete = rg_var_uint('delete');
499 while ($delete == 1) {
500 if (!rg_valid_referer()) {
501 $errmsg[] = 'invalid referer; try again';
502 break;
503 }
504
505 if (!rg_token_valid($db, $rg, 'ldap_list', FALSE)) {
506 $errmsg[] = 'invalid token; try again.';
507 break;
508 }
509
510 $list = rg_var_str('delete_list');
511 $r = rg_ldap_remove($db, $list);
512 if ($r['ok'] !== 1) {
513 $errmsg[] = 'cannot delete: ' . rg_ldap_error();
514 break;
515 }
516
517 $ret .= rg_template('admin/ldap/delete_ok.html',
518 $rg, TRUE /*xss*/);
519 break;
520 }
521 if (!empty($errmsg)) {
522 $rg['HTML:errmsg'] = rg_template_errmsg($errmsg);
523 $ret .= rg_template('admin/ldap/delete_err.html',
524 $rg, TRUE /*xss*/);
525 }
526
527 $r = rg_ldap_list($db);
528 if ($r['ok'] !== 1) {
529 $rg['errmsg'] = rg_ldap_error();
530 $ret .= rg_template('admin/ldap/list_err.html',
531 $rg, TRUE /*xss*/);
532 } else {
533 rg_ldap_cosmetic($db, $r['list']);
534 $rg['rg_form_token'] = rg_token_get($db, $rg, 'ldap_list');
535 $ret .= rg_template_table('admin/ldap/list', $r['list'], $rg);
536 }
537
538 rg_log_exit();
539 rg_prof_end('ldap_list_high_level');
540 return $ret;
541 }
542
543 /*
544 * High level function to add/edit a LDAP server
545 */
546 function rg_ldap_add_high_level($db, $rg, $op, $paras)
547 {
548 rg_prof_start('ldap_add_high_level');
549 rg_log_enter('ldap_add_high_level op=' . $op);
550
551 rg_log('DEBUG: paras:' . rg_array2string($paras));
552
553 $ret = '';
554 $errmsg = array();
555 $show_form = TRUE;
556
557 $rg['ldap'] = array();
558
559 if (strcmp($op, 'add') == 0) {
560 $rg['ldap']['id'] = 0;
561 } else { // edit
562 if (isset($paras[0]))
563 $rg['ldap']['id'] = intval($paras[0]);
564 else
565 $rg['ldap']['id'] = 0;
566 }
567
568 $doit = rg_var_uint('doit');
569 while ($doit == 1) {
570 if (!rg_valid_referer()) {
571 $errmsg[] = 'invalid referer; try again';
572 break;
573 }
574
575 if (!rg_token_valid($db, $rg, 'ldap_add', FALSE)) {
576 $errmsg[] = 'invalid token; try again.';
577 break;
578 }
579
580 $rg['ldap'] = array(
581 'id' => rg_var_uint('ldap::id'),
582 'name' => rg_var_str('ldap::name'),
583 'plan_id' => rg_var_uint('ldap::plan_id'),
584 'prio' => rg_var_uint('ldap::prio'),
585 'session_time' => rg_var_uint('ldap::session_time'),
586 'url' => rg_var_str('ldap::url'),
587 'bind_dn' => rg_var_str('ldap::bind_dn'),
588 'bind_pass' => rg_var_str('ldap::bind_pass'),
589 'user_base' => rg_var_str('ldap::user_base'),
590 'uid_attr' => rg_var_str('ldap::uid_attr'),
591 'filter' => rg_var_str('ldap::filter'),
592 'group_base' => rg_var_str('ldap::group_base'),
593 'group_attr' => rg_var_str('ldap::group_attr'),
594 'group_filter' => rg_var_str('ldap::group_filter'),
595 'admin_group' => rg_var_str('ldap::admin_group'),
596 'ca_cert' => rg_var_str('ldap::ca_cert')
597 );
598
599 $r = rg_ldap_add($db, $rg['login_ui']['uid'], $rg['ldap']);
600 if ($r['ok'] !== 1) {
601 $errmsg[] = rg_ldap_error();
602 break;
603 }
604
605 $ret .= rg_template('admin/ldap/edit_ok.html',
606 $rg, TRUE /*xss*/);
607
608 $show_form = FALSE;
609 break;
610 }
611
612 $hints = array();
613 if ($show_form) {
614 if ($doit == 0) {
615 // Loading defaults values
616 if (strcmp($op, 'add') == 0) {
617 $rg['ldap'] = array(
618 'id' => 0,
619 'name' => '',
620 'plan_id' => 0,
621 'prio' => 0,
622 'session_time' => 3600,
623 'url' => '',
624 'bind_dn' => '',
625 'bind_pass' => '',
626 'user_base' => '',
627 'uid_attr' => '',
628 'filter' => '',
629 'group_base' => '',
630 'group_attr' => '',
631 'group_filter' => '',
632 'admin_group' => '',
633 'ca_cert' => ''
634 );
635 } else { // edit
636 $_id = $rg['ldap']['id'];
637 $r = rg_ldap_list($db);
638 if ($r['ok'] != 1) {
639 $errmsg[] = 'cannot load info; try again later';
640 } else if (!isset($r['list'][$_id])) {
641 $errmsg[] = 'invalid id';
642 } else {
643 $rg['ldap'] = $r['list'][$_id];
644 }
645 }
646 }
647
648 $rg['HTML:select_plan'] = rg_plan_select($db, 'ldap::plan-id',
649 $rg['ldap']['plan_id']);
650
651 $hints[]['HTML:hint'] = rg_template(
652 'admin/ldap/hints.html', $rg, TRUE /*xss*/);
653
654 $rg['HTML:errmsg'] = rg_template_errmsg($errmsg);
655 $rg['rg_form_token'] = rg_token_get($db, $rg, 'ldap_add');
656 $ret .= rg_template('admin/ldap/add_edit.html',
657 $rg, TRUE /*xss*/);
658 } else {
659 $hints[]['HTML:hint'] = rg_template(
660 'admin/ldap/hints.html', $rg, TRUE /*xss*/);
661 }
662
663 $ret .= rg_template_table('hints/list', $hints, $rg);
664
665 rg_log_exit();
666 rg_prof_end('ldap_add_high_level');
667 return $ret;
668 }
669
670 /*
671 * Main HL function for LDAP
672 * (Admin -> LDAP)
673 */
674 function rg_ldap_high_level($db, &$rg, $paras)
675 {
676 rg_prof_start('ldap_high_level');
677 rg_log_enter('ldap_high_level');
678
679 $ret = '';
680 while (1) {
681 $op = empty($paras) ? 'list' : array_shift($paras);
682 $rg['menu']['ldap'][$op] = 1;
683
684 $rg['HTML:menu_level2'] =
685 rg_template('admin/ldap/menu.html', $rg, TRUE /*xss*/);
686
687 switch ($op) {
688 case 'add':
689 case 'edit':
690 $ret .= rg_ldap_add_high_level($db, $rg, $op, $paras);
691 break;
692
693 default:
694 $ret .= rg_ldap_list_high_level($db, $rg, $paras);
695 break;
696 }
697
698 break;
699 }
700
701 rg_log_exit();
702 rg_prof_end('ldap_high_level');
703 return $ret;
704 }
705
706 ?>
File inc/ldap_core.inc.php added (mode: 100644) (index 0000000..92ed4fd)
1 <?php
2 require_once($INC . "/sql.inc.php");
3 require_once($INC . "/state.inc.php");
4 require_once($INC . "/prof.inc.php");
5
6 $rg_ldap_core_error = '';
7
8 function rg_ldap_core_set_error($str)
9 {
10 global $rg_ldap_core_error;
11 $rg_ldap_core_error = $str;
12 rg_log($str);
13 }
14
15 function rg_ldap_core_error()
16 {
17 global $rg_ldap_core_error;
18 return $rg_ldap_core_error;
19 }
20
21 /*
22 * Connects to a ldap server
23 */
24 function rg_ldap_core_connect($server)
25 {
26 $ret = array('ok' => 0);
27 while (1) {
28 //ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, 7);
29
30 $r = ldap_connect($server);
31 if ($r === FALSE) {
32 $ret['errmsg'] = 'cannot connect to LDAP server';
33 break;
34 }
35
36 // http://php.net/manual/en/function.ldap-set-option.php
37 ldap_set_option($r, LDAP_OPT_PROTOCOL_VERSION, 3);
38 ldap_set_option($r, LDAP_OPT_DEREF, LDAP_DEREF_ALWAYS);
39 ldap_set_option($r, LDAP_OPT_TIMELIMIT, 10);
40 ldap_set_option($r, LDAP_OPT_NETWORK_TIMEOUT, 10);
41 //ldap_set_option($r, LDAP_OPT_DEBUG_LEVEL, 7);
42
43 $ret['con'] = $r;
44 $ret['ok'] = 1;
45 break;
46 }
47
48 return $ret;
49 }
50
51 /*
52 * LDAP bind
53 */
54 function rg_ldap_core_bind($con, $rdn, $pass)
55 {
56 $ret = array('ok' => 0);
57 while (1) {
58 $r = @ldap_bind($con, $rdn, $pass);
59 if ($r !== TRUE) {
60 ldap_get_option($con, LDAP_OPT_ERROR_STRING, $e);
61 $ret['errmsg'] = ldap_error($con) . ' [' . $e . ']';
62 break;
63 }
64
65 $ret['ok'] = 1;
66 break;
67 }
68
69 return $ret;
70 }
71
72 /*
73 * ldap_add wrapper
74 */
75 function rg_ldap_core_add($con, $dn, $entry)
76 {
77 $ret = array('ok' => 0);
78 while (1) {
79 $r = @ldap_add($con, $dn, $entry);
80 if ($r !== TRUE) {
81 ldap_get_option($con, LDAP_OPT_ERROR_STRING, $e);
82 $ret['errmsg'] = ldap_error($con) . ' [' . $e . ']';
83 break;
84 }
85
86 $ret['ok'] = 1;
87 break;
88 }
89
90 return $ret;
91 }
92
93 /*
94 * ldap_delete wrapper
95 */
96 function rg_ldap_core_del($con, $dn)
97 {
98 $ret = array('ok' => 0);
99 while (1) {
100 $r = @ldap_delete($con, $dn);
101 if ($r !== TRUE) {
102 ldap_get_option($con, LDAP_OPT_ERROR_STRING, $e);
103 $ret['errmsg'] = ldap_error($con) . ' [' . $e . ']';
104 break;
105 }
106
107 $ret['ok'] = 1;
108 break;
109 }
110
111 return $ret;
112 }
113
114 /*
115 * LDAP search
116 * @attr - array('mail', 'sn' etc.)
117 * @attronly - 1 to return only the attr types (no values). Else 0.
118 * @sizelimit - 0 = all entries
119 * @timelimit - in seconds, 0 = unlimited
120 * @deref - LDAP_DEREF_ NEVER SEARCHING FINDING ALWAYS
121 */
122 function rg_ldap_core_search($con, $base_dn, $filter, $attr, $attronly,
123 $sizelimit, $timelimit, $deref)
124 {
125 rg_log_enter('ldap_core_search');
126
127 $ret = array();
128 $ret['ok'] = 0;
129 while (1) {
130 $r = @ldap_search($con, $base_dn, $filter, $attr, $attronly,
131 $sizelimit, $timelimit, $deref);
132 if ($r === FALSE) {
133 ldap_get_option($con, LDAP_OPT_ERROR_STRING, $e);
134 $ret['errmsg'] = ldap_error($con) . ' [' . $e . ']';
135 break;
136 }
137
138 $ret['data'] = @ldap_get_entries($con, $r);
139 if ($ret['data'] === FALSE) {
140 ldap_get_option($con, LDAP_OPT_ERROR_STRING, $e);
141 $ret['errmsg'] = ldap_error($con) . ' [' . $e . ']';
142 break;
143 }
144 //rg_log_ml('DEBUG: entries: ' . print_r($ret['data'], TRUE));
145
146 $ret['ok'] = 1;
147 break;
148 }
149
150 rg_log_exit();
151 return $ret;
152 }
153
154 /*
155 * Implemet ldap_list here! TODO - must faster than search (subtree)
156 * ldap_list (one level)
157 */
158
159
160 /*
161 * LDIF -> array
162 * Returns how many bytes were processed.
163 */
164 function rg_ldap_core_ldif2array($data)
165 {
166 $ret = array();
167 $ret['ok'] = 0;
168 $ret['data'] = array();
169
170 $i = 0;
171 $off = 0;
172 while (1) {
173 rg_log('off=' . $off);
174 $ret['used'] = $off;
175
176 // Do we have more data in buffer?
177 if (strlen(substr($data, $off, 1)) == 0) {
178 rg_log('buffer is empty');
179 $ret['ok'] = 1;
180 break;
181 }
182
183 // Check if we have a full block
184 $end = strpos($data, "\n\n", $off);
185 if ($end === FALSE) {
186 rg_log('cannot find another \n\n');
187 $ret['ok'] = 1;
188 break;
189 }
190 $end += 1; // we will point to the second \n
191 rg_log('end = ' . $end);
192
193 $error = FALSE;
194 while (1) {
195 rg_log('DEBUG: looping again, off=' . $off);
196 if ($off === $end) {
197 rg_log('off is at the end');
198 $off = $end + 1;
199 $i++;
200 break;
201 }
202
203 $cr = strpos($data, "\n", $off);
204 rg_log('cr is at pos ' . $cr);
205
206 if (substr_compare($data, '#', $off, 1) == 0) {
207 $off = $cr + 1;
208 continue;
209 }
210 $sc = strpos($data, ':', $off);
211 rg_log('sc = ' . $sc);
212
213 if (($sc === FALSE) || ($cr < $sc)) {
214 $ret['errmsg'] = 'entry without \':\' at offset ' . $off;
215 $error = TRUE;
216 break;
217 }
218
219 if (!isset($ret['data'][$i]))
220 $ret['data'][$i] = array();
221
222 $k = substr($data, $off, $sc - $off);
223 rg_log('k=' . $k . '.');
224 $v = substr($data, $sc + 1, $cr - $sc - 1);
225 if (strncmp($v, ':', 1) == 0) {
226 $v = base64_decode(substr($v, 1));
227 if ($v === FALSE) {
228 $ret['errmsg'] = 'base64 decode error at offset ' . $off;
229 $error = TRUE;
230 break;
231 }
232 } else if (strncmp($v, ' ', 1) == 0) {
233 $v = substr($v, 1);
234 } else {
235 $ret['errmsg'] = 'invalid character after \':\' at offset ' . $off;
236 $error = TRUE;
237 break;
238 }
239
240 if (!isset($ret['data'][$i][$k]))
241 $ret['data'][$i][$k] = array();
242 $ret['data'][$i][$k][] = $v;
243 $off = $cr + 1;
244 }
245 if ($error)
246 break;
247 }
248
249 return $ret;
250 }
251
252 ?>
File inc/ldap_sync.inc.php added (mode: 100644) (index 0000000..c3b86e4)
1 <?php
2 require_once($INC . "/sql.inc.php");
3 require_once($INC . "/state.inc.php");
4 require_once($INC . "/prof.inc.php");
5 require_once($INC . "/ldap_core.inc.php");
6
7 /*
8 * Get data from cache
9 */
10 function rg_ldap_sync_get_cache($db, $v)
11 {
12 rg_log_enter('ldap_sync_get_cache');
13
14 $ret = array('ok' => 0);
15 while (1) {
16 $params = array('v' => $v);
17 $sql = 'SELECT * FROM ldap_cache'
18 . ' WHERE mail = @@v@@'
19 . ' OR ldap_uid = @@v@@'
20 . ' OR cn = @@v@@'
21 . ' ORDER BY prio';
22 $res = rg_sql_query_params($db, $sql, $params);
23 if ($res === FALSE) {
24 $ret['errmsg'] = 'cannot select from cache';
25 break;
26 }
27
28 $ret['list'] = array();
29 while (($row = rg_sql_fetch_array($res)))
30 $ret['list'][] = $row;
31
32 rg_sql_free_result($res);
33
34 $ret['ok'] = 1;
35 break;
36 }
37
38 rg_log_exit();
39 return $ret;
40 }
41
42 /*
43 * Updates ldap_cache table
44 * TODO: should be moved to ldap.inc.php because is called from there?
45 * And get rid of "_sync_" in name.
46 */
47 function rg_ldap_sync_update_cache($db, $l)
48 {
49 rg_log_enter('ldap_sync_update_cache');
50
51 rg_log_ml('DEBUG: l: ' . print_r($l, TRUE));
52
53 $ret = array('ok' => 0);
54 while (1) {
55 // We update uid only if != 0
56 $add = '';
57 if ($l['uid'] > 0)
58 $add .= ', uid = @@uid@@';
59
60 $sql = 'UPDATE ldap_cache SET'
61 . ' ldap_uid = @@ldap_uid@@'
62 . $add
63 . ', password = @@password@@'
64 . ', sn = @@sn@@'
65 . ', gn = @@gn@@'
66 . ', gid = @@gid@@'
67 . ', mail = @@mail@@'
68 . ', cn = @@cn@@'
69 . ', shadow_expire = @@shadow_expire@@'
70 . ' WHERE server_id = @@server_id@@'
71 . ' AND uuid = @@uuid@@';
72 $res = rg_sql_query_params($db, $sql, $l);
73 if ($res === FALSE) {
74 $ret['errmsg'] = 'error in update';
75 break;
76 }
77 $arows = rg_sql_affected_rows($res);
78 rg_sql_free_result($res);
79
80 if ($arows > 0) {
81 $ret['ok'] = 1;
82 break;
83 }
84
85 $sql = 'INSERT INTO ldap_cache (uid, ldap_uid, password'
86 . ', sn, gn, gid, mail, cn, shadow_expire'
87 . ', server_id, uuid)'
88 . ' VALUES (@@uid@@, @@ldap_uid@@, @@password@@'
89 . ', @@sn@@, @@gn@@, @@gid@@, @@mail@@'
90 . ', @@cn@@, @@shadow_expire@@, @@server_id@@'
91 . ', @@uuid@@)';
92 $ignore = array(RG_SQL_UNIQUE_VIOLATION);
93 $res = rg_sql_query_params_ignore($db, $sql, $l,
94 $ignore, $ignore_kicked);
95 if ($res === FALSE) {
96 if (!$ignore_kicked) {
97 $ret['errmsg'] = 'error in update';
98 break;
99 }
100 rg_log('Entry already in cache.');
101 } else {
102 rg_sql_free_result($res);
103 }
104
105 $ret['ok'] = 1;
106 break;
107 }
108
109 rg_log_exit();
110 return $ret;
111 }
112
113 /*
114 * Updates ldap_servers table - for now, CSNs
115 * TODO: It should be used to set also the last error message?
116 * Maybe we should have a different log for this kind of problems,
117 * and send it to the admin.
118 */
119 function rg_ldap_sync_update_server($db, $server_id, $csn)
120 {
121 rg_log_enter('ldap_sync_update_server');
122
123 $ret = array('ok' => 0);
124 while (1) {
125 if (empty($csn)) {
126 $ret['ok'] = 1;
127 break;
128 }
129
130 $params = array(
131 'server_id' => $server_id,
132 'csn' => $csn
133 );
134 $sql = 'UPDATE ldap_servers SET'
135 . ' csn = @@csn@@'
136 . ' WHERE id = @@server_id@@';
137 $res = rg_sql_query_params($db, $sql, $params);
138 if ($res === FALSE) {
139 $ret['errmsg'] = 'error in update';
140 break;
141 }
142 rg_sql_free_result($res);
143
144 $ret['ok'] = 1;
145 break;
146 }
147
148 rg_log_exit();
149 return $ret;
150 }
151
152 /*
153 * It applies the updates to the database.
154 * Input is a ldif parsed as an array (from rg_ldap_core_ldif2array)
155 */
156 function rg_ldap_sync_apply($db, $server_id, $data)
157 {
158 rg_log_enter('ldap_sync_apply');
159
160 $ret = array();
161 $ret['ok'] = 0;
162 while (1) {
163 rg_log_ml('data: ' . print_r($data, TRUE));
164
165 if (rg_sql_begin($db) !== TRUE) {
166 $ret['errmsg'] = 'cannot start transaction';
167 break;
168 }
169 $rollback = TRUE;
170
171 $csn = array();
172 foreach ($data as $block_id => $block) {
173 if (isset($block['entryCSN'][0])) {
174 rg_log('DEBUG: entryCSN is present!');
175 $c = $block['entryCSN'][0];
176 // Example: 20171001075924.155248Z#000000#001#000000
177 $_t = explode('#', $c);
178 $_s = isset($_t[2]) ? $_t[2] : '';
179 if (!isset($csn[$_s]) || ($c > $csn[$_s]))
180 $csn[$_s] = $c;
181 } else {
182 rg_log('DEBUG: entryCSN is NOT present!');
183 }
184
185 if (!isset($block['objectClass'])) {
186 $ret['errmsg'] = 'missing objectClass';
187 break;
188 }
189
190 // Try to detect if is a user entry
191 $is_user = FALSE;
192 foreach ($block['objectClass'] as $oc) {
193 if (strcasecmp($oc, 'inetOrgPerson') == 0) {
194 $is_user = TRUE;
195 break;
196 }
197 }
198
199 if (!$is_user)
200 continue;
201
202 $l = array();
203 $l['uid'] = 0;
204 $l['ldap_uid'] = isset($block['uid'][0]) ? $block['uid'][0] : '';
205 $l['password'] = isset($block['userPassword'][0]) ? $block['userPassword'][0] : '';
206 $l['sn'] = isset($block['sn'][0]) ? $block['sn'][0] : '';
207 $l['gn'] = isset($block['givenName'][0]) ? $block['givenName'][0] : '';
208 $l['gid'] = isset($block['gidNumber'][0]) ? $block['gidNumber'][0] : 0;
209 $l['mail'] = isset($block['mail'][0]) ? $block['mail'][0] : '';
210 $l['cn'] = isset($block['cn'][0]) ? $block['cn'][0] : '';
211 $l['shadow_expire'] = isset($block['shadowExpire'][0]) ? $block['shadowExpire'][0] : '99999';
212 $l['server_id'] = $server_id;
213 $l['uuid'] = isset($block['entryUUID'][0]) ? $block['entryUUID'][0] : '';
214 // Verifications
215 if (empty($l['ldap_uid'])) {
216 rg_log('DEBUG: ldap_uid is not present!');
217 continue;
218 }
219 if (empty($l['uuid'])) {
220 rg_log('DEBUG: entryUUID is not present!');
221 continue;
222 }
223
224 rg_log_ml('DEBUG: l:' . print_r($l, TRUE));
225
226 $r = rg_ldap_sync_update_cache($db, $l);
227 if ($r['ok'] !== 1) {
228 $r['errmsg'] = $r['errmsg'];
229 break;
230 }
231
232 /*
233 TODO foreach ($block['memberOf'] as $m)
234 $pairs_groups[] = array($uuid, $m);
235 */
236 }
237 if (isset($ret['errmsg']))
238 break;
239
240 rg_log_ml('DEBUG: csn: ' . print_r($csn, TRUE));
241 $r = rg_ldap_sync_update_server($db, $server_id,
242 implode(';', $csn));
243 if ($r['ok'] !== 1) {
244 $ret['errmsg'] = $r['errmsg'];
245 break;
246 }
247
248 if (rg_sql_commit($db) !== TRUE) {
249 $ret['errmsg'] = 'cannot commit';
250 break;
251 }
252
253 $ret['ok'] = 1;
254 $rollback = FALSE;
255 break;
256 }
257
258 if ($rollback)
259 rg_sql_rollback($db);
260
261 rg_log_exit();
262 return $ret;
263 }
264
265 /*
266 * Function called to process raw ldif blocks -> database
267 */
268 function rg_ldap_sync_data($db, $server_id, $s)
269 {
270 rg_log_enter('ldap_sync_data');
271 rg_log('DEBUG: s=' . $s);
272
273 $ret = array();
274 $ret['ok'] = 0;
275 while (1) {
276 $a = rg_ldap_core_ldif2array($s);
277 if ($a['ok'] != 1) {
278 $ret['errmsg'] = $a['errmsg'];
279 break;
280 }
281
282 // Update database
283 if (!empty($a['data'])) {
284 $r = rg_ldap_sync_apply($db, $server_id, $a['data']);
285 if ($r['ok'] != 1) {
286 $ret['errmsg'] = $r['errmsg'];
287 break;
288 }
289 }
290
291 $ret['ok'] = 1;
292 $ret['used'] = $a['used'];
293 break;
294 }
295
296 rg_log_exit();
297 return $ret;
298 }
299
300 /*
301 * 'input' callback for rg_ldap_sync_* functions
302 */
303 function rg_ldap_sync_cb_input($index, &$info, $stream)
304 {
305 rg_log_enter('ldap_sync_cb_input: index=' . $index
306 . ' stream=' . $stream);
307
308 while (1) {
309 //rg_log_ml('info: ' . print_r($info, TRUE));
310
311 $c = &$info['custom'];
312
313 switch ($stream) {
314 case 1:
315 //rg_log('Got data: ' . $info['in_buf']);
316 $r = rg_ldap_sync_data($c['db'], $c['server_id'],
317 $info['in_buf']);
318 if ($r['ok'] != 1) {
319 rg_log('Error: ' . $r['errmsg']);
320 $info['done'] = TRUE;
321 break;
322 }
323
324 $info['in_buf'] = substr($info['in_buf'], $r['used']);
325 break;
326
327 case 2:
328 // TODO: should we do something with this?
329 // Maybe store it in the synchronization log?
330 // Send it do admin?
331 rg_log_ml('error received: ' . $info['err_buf']);
332 $info['err_buf'] = '';
333 break;
334 }
335
336 break;
337 }
338
339 rg_log_exit();
340 }
341
342 /*
343 * 'error' calback for rg_ldap_sync_* functions
344 */
345 function rg_ldap_sync_cb_error($index, &$info, $msg)
346 {
347 rg_log('ldap_sync_cb_error: ' . $msg);
348 $info['done'] = TRUE;
349 }
350
351 /*
352 * Sync function using SyncRepl protocol (ro way)
353 */
354 function rg_ldap_sync_ro($db, $data)
355 {
356 // TODO: move this in the higher level part
357 // Load the list of servers in decreasing priority order
358 // because we want the best one to overwrite the lower priority ones.
359
360 // Hm! Have a problem: sync_rp with multiple servers!
361
362 $ret = array();
363 $ret['ok'] = 0;
364 while (1) {
365 // Store password
366 $r = rg_id(16);
367 // TODO: choose a better name; choose a better dir
368 $pass_file = '/tmp/' . $r;
369 $f = @fopen($pass_file, 'w');
370 if ($f === FALSE) {
371 $ret['errmsg'] = 'cannot create pass file';
372 break;
373 }
374 if (@chmod($pass_file, 0600) !== TRUE) {
375 fclose($f);
376 $ret['errmsg'] = 'cannot chmod pass';
377 break;
378 }
379
380 $r = @fwrite($f, $data['bind_pass']);
381 if ($r === FALSE) {
382 fclose($f);
383 $ret['errmsg'] = 'cannot write pass';
384 break;
385 }
386
387 fclose($f);
388
389 $cmd = 'ldapsearch -d-1 -LLL -v -b ' . escapeshellarg($data['base'])
390 . ' -x -H ldap://' . escapeshellarg($data['addr'])
391 . ':' . escapeshellarg($data['port'])
392 . ' -D ' . escapeshellarg($data['bind_user'])
393 . ' -y ' . escapeshellarg($pass_file)
394 . ' -s sub -P 3';
395 if (isset($data['rid']) && isset($data['csn'])) {
396 $cmd .= ' -E ' . escapeshellarg('sync=ro/'
397 . 'rid=' . $data['rid']
398 . ',sid=001'
399 . ',csn=' . $data['csn']);
400 } else {
401 $cmd .= ' -E sync=ro/rid=001,sid=001,csn=aaa';
402 }
403
404 if (isset($data['fields'])) {
405 $fields = '';
406 $add = '';
407 foreach($data['fields'] as $f) {
408 $fields .= $add . $f;
409 $add = ',';
410 }
411 } else {
412 $fields = '*';
413 }
414
415 $cmd .= ' "(|'
416 . '(objectClass=groupOfNames)'
417 . '(objectClass=groupOfUniqueNames)'
418 . '(structuralObjectClass=inetOrgPerson)'
419 . ')"';
420 $cmd .= ' ' . escapeshellarg($fields) . ' +';
421 $a = array(
422 'cmds' => array(
423 'cmd1' => array(
424 'cmd' => $cmd,
425 'cb_input' => 'rg_ldap_sync_cb_input',
426 'cb_error' => 'rg_ldap_sync_cb_error',
427 'custom' => array(
428 'db' => $db,
429 'server_id' => $data['server_id']
430 )
431 )
432 )
433 );
434 $r = rg_exec2($a);
435 @unlink($pass_file);
436 if ($r['ok'] != 1) {
437 $ret['errmsg'] = $r['errmsg'];
438 break;
439 }
440
441 $ret['ok'] = 1;
442 break;
443 }
444
445 return $ret;
446 }
447
448 ?>
File inc/log.inc.php changed (mode: 100644) (index f46c541..a574f6f)
... ... function rg_log($str)
70 70
71 71 $t = gettimeofday(); $t = gettimeofday();
72 72
73 $buf0 = gmdate('Y-m-d H:i:s', $t['sec']) . "." . sprintf('%03u', $t['usec'] / 1000);
73 $buf0 = gmdate('H:i:s', $t['sec']) . '.'
74 . sprintf('%03u', $t['usec'] / 1000);
74 75 if (strcmp($rg_log_sid, '000000') != 0) if (strcmp($rg_log_sid, '000000') != 0)
75 $buf0 .= " " . $rg_log_sid;
76 $buf = "";
76 $buf0 .= ' ' . $rg_log_sid;
77 $buf = '';
77 78 $str2 = preg_replace_callback('/[^\pL\pN\pP\pS \t]/uU', $str2 = preg_replace_callback('/[^\pL\pN\pP\pS \t]/uU',
78 79 'rg_callback_hexa', $str); 'rg_callback_hexa', $str);
79 80 if ($str2 === NULL) // try without utf-8 if ($str2 === NULL) // try without utf-8
 
... ... function rg_fatal($msg)
189 190 exit(1); exit(1);
190 191 } }
191 192
193 $rg_internal_error_last = '';
192 194 function rg_internal_error($msg) function rg_internal_error($msg)
193 195 { {
196 global $rg_internal_error_last;
197
198 $rg_internal_error_last = $msg;
194 199 rg_error_core("Internal error: $msg"); rg_error_core("Internal error: $msg");
195 200 } }
196 201
File inc/login/login.php changed (mode: 100644) (index 66a34d0..5254664)
... ... while ($rg['doit'] == 1) {
23 23
24 24 $r = rg_user_login_by_user_pass($db, $user, $pass, $login_token, $r = rg_user_login_by_user_pass($db, $user, $pass, $login_token,
25 25 $lock_ip, $rg['hostname'], $rg['login_ui']); $lock_ip, $rg['hostname'], $rg['login_ui']);
26 if ($r === FALSE) {
27 $errmsg[] = rg_user_error();
26 if ($r['ok'] !== 1) {
27 $errmsg[] = $r['errmsg'];
28 28 break; break;
29 29 } }
30 30
File inc/plan.inc.php changed (mode: 100644) (index a39864b..9f8fa06)
... ... function rg_plan_info($db, $id)
180 180 $ret = array(); $ret = array();
181 181 $ret['ok'] = 0; $ret['ok'] = 0;
182 182 $ret['exists'] = 0; $ret['exists'] = 0;
183
184 183 while (1) { while (1) {
185 184 $list = rg_plan_list($db); $list = rg_plan_list($db);
186 185 if ($list === FALSE) if ($list === FALSE)
 
... ... function rg_plan_info($db, $id)
203 202
204 203 /* /*
205 204 * Returns a select list * Returns a select list
205 * @name - the variable name
206 206 */ */
207 function rg_plan_select($db, $plan_id)
207 function rg_plan_select($db, $name, $plan_id)
208 208 { {
209 209 $list = rg_plan_list($db); $list = rg_plan_list($db);
210 210 if ($list === FALSE) if ($list === FALSE)
211 211 return rg_warning("Could not load plans."); return rg_warning("Could not load plans.");
212 212
213 $ret = "<select name=\"plan_id\" id=\"plan_id\">\n";
213 $ret = "<select name=\"" . $name . "\" id=\"plan_id\">\n";
214 214 foreach ($list as $row) { foreach ($list as $row) {
215 215 $add = ""; $add = "";
216 216 if ($row['id'] == $plan_id) if ($row['id'] == $plan_id)
 
... ... function rg_plan_select($db, $plan_id)
230 230 */ */
231 231 function rg_plan_list_high_level($db, $rg) function rg_plan_list_high_level($db, $rg)
232 232 { {
233 $ret = "";
233 rg_log_enter('plan_high_list');
234 234
235 $list_errmsg = array();
236 $del_errmsg = array();
235 $ret = '';
237 236
238 $delete = rg_var_uint("delete");
239 while (1) {
240 if ($delete != 1)
241 break;
237 $del_errmsg = array();
242 238
239 $delete = rg_var_uint('delete');
240 while ($delete == 1) {
243 241 if (!rg_valid_referer()) { if (!rg_valid_referer()) {
244 242 $del_errmsg[] = 'invalid referer; try again'; $del_errmsg[] = 'invalid referer; try again';
245 243 break; break;
 
... ... function rg_plan_list_high_level($db, $rg)
250 248 break; break;
251 249 } }
252 250
253 $list = rg_var_str("delete_list");
254
251 $list = rg_var_str('delete_list');
255 252 $r = rg_plan_remove($db, $list); $r = rg_plan_remove($db, $list);
256 253 if ($r !== TRUE) { if ($r !== TRUE) {
257 254 $rg['errmsg'] = rg_plan_error(); $rg['errmsg'] = rg_plan_error();
258 $del_errmsg[] = rg_template("admin/plans/delete_err.html", $rg, TRUE /* xss */);
255 $del_errmsg[] = rg_template(
256 'admin/plans/delete_err.html',
257 $rg, TRUE /*xss*/);
259 258 break; break;
260 259 } }
261 260 break; break;
262 261 } }
263 262
263 $errmsg = array();
264 264 $list = rg_plan_list($db); $list = rg_plan_list($db);
265 265 if ($list === FALSE) { if ($list === FALSE) {
266 266 $rg['errmsg'] = rg_plan_error(); $rg['errmsg'] = rg_plan_error();
267 267 // TODO: really? no array append?! // TODO: really? no array append?!
268 return rg_template("admin/plans/list_err.html", $rg, TRUE /* xss */);
268 return rg_template('admin/plans/list_err.html',
269 $rg, TRUE /*xss*/);
270 } else {
271 $rg['rg_form_token'] = rg_token_get($db, $rg, 'plan_list');
272 $rg['HTML:del_errmsg'] = rg_template_errmsg($del_errmsg);
273 $ret .= rg_template_table("admin/plans/list", $list, $rg);
269 274 } }
270 275
271 $rg['rg_form_token'] = rg_token_get($db, $rg, 'plan_list');
272 $rg['HTML:del_errmsg'] = rg_template_errmsg($del_errmsg);
273 $ret .= rg_template_table("admin/plans/list", $list, $rg);
276 rg_log_exit();
274 277 return $ret; return $ret;
275 278 } }
276 279
File inc/repo.inc.php changed (mode: 100644) (index 7b218f0..9fc8140)
... ... function rg_repo_insert_rename($db, $uid, $repo_id, $old_name)
1034 1034 . " (" . rg_sql_error() . ")"); . " (" . rg_sql_error() . ")");
1035 1035 break; break;
1036 1036 } }
1037 rg_sql_free_result($res);
1037 1038
1038 1039 rg_cache_set("repo_by_name::$uid::$old_name", $repo_id, RG_SOCKET_NO_WAIT); rg_cache_set("repo_by_name::$uid::$old_name", $repo_id, RG_SOCKET_NO_WAIT);
1039 1040
 
... ... function rg_repo_lock($db, $repo_id, $uid, $lock, $reason)
1511 1512 rg_repo_set_error('db lock/unlock error'); rg_repo_set_error('db lock/unlock error');
1512 1513 break; break;
1513 1514 } }
1515 rg_sql_free_result($res);
1514 1516
1515 1517 $key = 'locks' . '::' . 'repos' . '::' . $repo_id; $key = 'locks' . '::' . 'repos' . '::' . $repo_id;
1516 1518 if ($lock == 1) { if ($lock == 1) {
 
... ... function rg_repo_fetch_push_helper($db, $host, $ip, $login_ui, $prefix, $user,
2430 2432 $needed_rights = 'P|H'; $needed_rights = 'P|H';
2431 2433 $ret['push'] = 1; $ret['push'] = 1;
2432 2434 } else { } else {
2433 $ret['error'] = 'unknown command';
2435 $ret['errmsg'] = 'unknown command';
2434 2436 break; break;
2435 2437 } }
2436 2438
2437 2439 // Validity/security checks // Validity/security checks
2438 2440 // Load info about the owner // Load info about the owner
2439 2441 if (rg_user_ok($user) !== TRUE) { if (rg_user_ok($user) !== TRUE) {
2440 $ret['error'] = 'user is invalid (' . rg_user_error() . ')';
2442 $ret['errmsg'] = 'user is invalid (' . rg_user_error() . ')';
2441 2443 break; break;
2442 2444 } }
2443 2445 $ret['owner_ui'] = rg_user_info($db, 0, $user, ''); $ret['owner_ui'] = rg_user_info($db, 0, $user, '');
2444 2446 if ($ret['owner_ui']['ok'] != 1) { if ($ret['owner_ui']['ok'] != 1) {
2445 $ret['error'] = 'internal problems; try again later, please';
2447 $ret['errmsg'] = 'internal problems; try again later, please';
2446 2448 break; break;
2447 2449 } }
2448 2450 if ($ret['owner_ui']['exists'] != 1) { if ($ret['owner_ui']['exists'] != 1) {
2449 $ret['error'] = 'user does not exists';
2451 $ret['errmsg'] = 'user does not exists';
2450 2452 break; break;
2451 2453 } }
2452 2454
 
... ... function rg_repo_fetch_push_helper($db, $host, $ip, $login_ui, $prefix, $user,
2454 2456
2455 2457 // Loading info about the repository // Loading info about the repository
2456 2458 if (rg_repo_ok($repo) !== TRUE) { if (rg_repo_ok($repo) !== TRUE) {
2457 $ret['error'] = 'repository is invalid ('
2459 $ret['errmsg'] = 'repository is invalid ('
2458 2460 . rg_repo_error() . ')'; . rg_repo_error() . ')';
2459 2461 break; break;
2460 2462 } }
2461 2463 $ret['ri'] = rg_repo_info($db, 0, $ret['owner_ui']['uid'], $repo); $ret['ri'] = rg_repo_info($db, 0, $ret['owner_ui']['uid'], $repo);
2462 2464 if ($ret['ri']['ok'] != 1) { if ($ret['ri']['ok'] != 1) {
2463 $ret['error'] = 'internal problems; try again later, please';
2465 $ret['errmsg'] = 'internal problems; try again later, please';
2464 2466 break; break;
2465 2467 } }
2466 2468 if ($ret['ri']['exists'] != 1) { if ($ret['ri']['exists'] != 1) {
2467 $ret['error'] = 'repository does not exists';
2469 $ret['errmsg'] = 'repository does not exists';
2468 2470 break; break;
2469 2471 } }
2470 2472 if ($ret['ri']['deleted'] == 1) { if ($ret['ri']['deleted'] == 1) {
2471 $ret['error'] = 'repository has been deleted';
2473 $ret['errmsg'] = 'repository has been deleted';
2472 2474 break; break;
2473 2475 } }
2474 2476
2475 2477 $ls = rg_repo_lock_status($db, $ret['ri']['repo_id']); $ls = rg_repo_lock_status($db, $ret['ri']['repo_id']);
2476 2478 if ($ls['ok'] != 1) { if ($ls['ok'] != 1) {
2477 $ret['error'] = 'could not get lock status: ' . rg_repo_error();
2479 $ret['errmsg'] = 'could not get lock status: ' . rg_repo_error();
2478 2480 break; break;
2479 2481 } }
2480 2482 if (($ls['status'] == 1) && ($login_ui['uid'] != $ls['uid'])) { if (($ls['status'] == 1) && ($login_ui['uid'] != $ls['uid'])) {
 
... ... function rg_repo_fetch_push_helper($db, $host, $ip, $login_ui, $prefix, $user,
2483 2485 $_user = $_u['username']; $_user = $_u['username'];
2484 2486 else else
2485 2487 $_user = '?'; $_user = '?';
2486 $ret['error'] = 'repository has been locked user ' . $_user
2488 $ret['errmsg'] = 'repository has been locked user ' . $_user
2487 2489 . ' at ' . gmdate('Y-m-d H:i', $ls['itime']) . ' UTC;' . ' at ' . gmdate('Y-m-d H:i', $ls['itime']) . ' UTC;'
2488 2490 . ' reason: ' . $ls['reason']; . ' reason: ' . $ls['reason'];
2489 2491 break; break;
 
... ... function rg_repo_fetch_push_helper($db, $host, $ip, $login_ui, $prefix, $user,
2509 2511 $r = rg_rights_allow($db, $x); $r = rg_rights_allow($db, $x);
2510 2512 // TODO: what if an error occured? How do we signal this?! $r must have ok key // TODO: what if an error occured? How do we signal this?! $r must have ok key
2511 2513 if ($r !== TRUE) { if ($r !== TRUE) {
2512 $ret['error'] = 'non existing repo or you are not allowed to push';
2514 $ret['errmsg'] = 'non existing repo or you are not allowed to push';
2513 2515 break; break;
2514 2516 } }
2515 2517
 
... ... function rg_repo_fetch_push_helper($db, $host, $ip, $login_ui, $prefix, $user,
2535 2537 $ip); $ip);
2536 2538 if (($r['ok'] !== 1) if (($r['ok'] !== 1)
2537 2539 || ($r['enrolled'] && empty($r['ip_list']))) { || ($r['enrolled'] && empty($r['ip_list']))) {
2538 $ret['error'] = rg_totp_error();
2540 $ret['errmsg'] = rg_totp_error();
2539 2541 $ret['ok'] = 0; $ret['ok'] = 0;
2540 2542 break; break;
2541 2543 } }
 
... ... function rg_repo_fetch_push_helper($db, $host, $ip, $login_ui, $prefix, $user,
2554 2556 // free space?! // free space?!
2555 2557 // We should mark the repo over limit when we compute // We should mark the repo over limit when we compute
2556 2558 // the disk space - same problem // the disk space - same problem
2557 $ret['error'] = 'cannot push: user is over limit'
2559 $ret['errmsg'] = 'cannot push: user is over limit'
2558 2560 . ' (' . $ret['owner_ui']['disk_used_mb'] . 'MiB >= ' . ' (' . $ret['owner_ui']['disk_used_mb'] . 'MiB >= '
2559 2561 . $max . 'MiB)'; . $max . 'MiB)';
2560 2562 break; break;
 
... ... function rg_repo_fetch_push_helper($db, $host, $ip, $login_ui, $prefix, $user,
2587 2589 $dst = $repo_path . '/refs/namespaces/' . $namespace . '/refs'; $dst = $repo_path . '/refs/namespaces/' . $namespace . '/refs';
2588 2590 $r = rg_copy_tree($repo_path . '/refs/heads', $dst . '/heads/', 0700); $r = rg_copy_tree($repo_path . '/refs/heads', $dst . '/heads/', 0700);
2589 2591 if ($r !== TRUE) { if ($r !== TRUE) {
2590 $ret['error'] = 'internal error (cannot copy heads refs)';
2592 $ret['errmsg'] = 'internal error (cannot copy heads refs)';
2591 2593 break; break;
2592 2594 } }
2593 2595 $r = rg_copy_tree($repo_path . '/refs/tags', $r = rg_copy_tree($repo_path . '/refs/tags',
2594 2596 $dst . '/tags/', 0700); $dst . '/tags/', 0700);
2595 2597 if ($r !== TRUE) { if ($r !== TRUE) {
2596 $ret['error'] =
2598 $ret['errmsg'] =
2597 2599 'internal error (cannot copy tags refs)'; 'internal error (cannot copy tags refs)';
2598 2600 break; break;
2599 2601 } }
File inc/sql.inc.php changed (mode: 100644) (index 10abc86..2b95172)
2 2 require_once($INC . "/log.inc.php"); require_once($INC . "/log.inc.php");
3 3 require_once($INC . "/prof.inc.php"); require_once($INC . "/prof.inc.php");
4 4
5 // Some constants for sql error codes
6 define('RG_SQL_UNIQUE_VIOLATION', '23505');
7
5 8 if (!function_exists("pg_connect")) if (!function_exists("pg_connect"))
6 9 die("FATAL: php PostgreSQL is not installed!"); die("FATAL: php PostgreSQL is not installed!");
7 10
11 if (!isset($rg_sql_debug))
12 $rg_sql_debug = 0;
13
8 14 $rg_sql_conn = array(); $rg_sql_conn = array();
9 15
10 16 $rg_sql_error = ""; $rg_sql_error = "";
 
... ... function rg_sql_set_error($str)
17 23 { {
18 24 global $rg_sql_error; global $rg_sql_error;
19 25 $rg_sql_error = $str; $rg_sql_error = $str;
20 rg_log($str);
26 rg_log('sql_set_error: ' . $str);
21 27 } }
22 28
23 29 function rg_sql_error() function rg_sql_error()
 
... ... function rg_sql_app($name)
42 48 */ */
43 49 function rg_sql_open_nodelay($h) function rg_sql_open_nodelay($h)
44 50 { {
45 global $php_errormsg;
46 51 global $rg_sql_debug; global $rg_sql_debug;
47 52 global $rg_sql_conn; global $rg_sql_conn;
48 53
49 rg_prof_start("sql_open_nodelay");
54 if ($rg_sql_debug > 20)
55 rg_log_enter('sql_open_nodelay');
50 56
51 57 $ret = FALSE; $ret = FALSE;
52 58 while (1) { while (1) {
 
... ... function rg_sql_open_nodelay($h)
55 61 break; break;
56 62 } }
57 63
64 if ($rg_sql_debug > 40) {
65 rg_log('My pid: ' . getmypid());
66 rg_log_ml('DEBUG: rg_sql_conn: ' . print_r($rg_sql_conn, TRUE));
67 }
68
58 69 if (isset($rg_sql_conn[$h]['db'])) { if (isset($rg_sql_conn[$h]['db'])) {
59 $ret = $rg_sql_conn[$h]['db'];
60 break;
70 if (getmypid() == $rg_sql_conn[$h]['pid']) {
71 if ($rg_sql_debug > 30)
72 rg_log('DB: Same pid, reuse connection');
73 $ret = $rg_sql_conn[$h]['db'];
74 break;
75 }
76
77 if ($rg_sql_debug > 25)
78 rg_log('DB: pid is different, reconnecting...');
79 unset($rg_sql_conn[$h]['db']);
61 80 } }
62 81
63 82 putenv('PGAPPNAME=' . $rg_sql_conn[$h]['app']); putenv('PGAPPNAME=' . $rg_sql_conn[$h]['app']);
 
... ... function rg_sql_open_nodelay($h)
66 85 if ($rg_sql_debug > 0) if ($rg_sql_debug > 0)
67 86 rg_log("DB: opening [$str]..."); rg_log("DB: opening [$str]...");
68 87
69 rg_prof_set(array("db_conn" => 1));
88 rg_prof_set(array('db_conn' => 1));
89
90 // This is used to test if we forked
91 $rg_sql_conn[$h]['pid'] = getmypid();
70 92
71 93 $_s = microtime(TRUE); $_s = microtime(TRUE);
72 94
 
... ... function rg_sql_open_nodelay($h)
88 110 $db = FALSE; $db = FALSE;
89 111 break; break;
90 112 } }
113 sleep(1);
91 114 } }
92 115 $diff = intval((microtime(TRUE) - $_s) * 1000); $diff = intval((microtime(TRUE) - $_s) * 1000);
93 rg_prof_set(array("db_c_ms" => $diff));
116 rg_prof_set(array('db_c_ms' => $diff));
94 117 if ($db === FALSE) { if ($db === FALSE) {
95 118 $err = 'cannot connect to database'; $err = 'cannot connect to database';
96 119 rg_sql_set_error($err); rg_sql_set_error($err);
 
... ... function rg_sql_open_nodelay($h)
104 127 break; break;
105 128 } }
106 129
107 rg_prof_end("sql_open_nodelay");
130 if ($rg_sql_debug > 20)
131 rg_log_exit();
108 132 return $ret; return $ret;
109 133 } }
110 134
 
... ... function rg_sql_open($str)
118 142 global $rg_sql_app; global $rg_sql_app;
119 143
120 144 $free_index = count($rg_sql_conn); $free_index = count($rg_sql_conn);
121 $rg_sql_conn[$free_index] = array();
122 $rg_sql_conn[$free_index]['str'] = $str;
123 $rg_sql_conn[$free_index]['app'] = $rg_sql_app;
145 $rg_sql_conn[$free_index] = array(
146 'str' => $str,
147 'app' => $rg_sql_app
148 );
124 149
125 150 //rg_log("Delay connection to [$str], index $free_index."); //rg_log("Delay connection to [$str], index $free_index.");
126 151 return $free_index; return $free_index;
 
... ... function rg_sql_escape($h, $str)
141 166 /* /*
142 167 * Helper for sql_query and sql_query_params * Helper for sql_query and sql_query_params
143 168 */ */
144 function rg_sql_query0($db, $sql, $res, $_s)
169 function rg_sql_query0($db, $sql, $r, $start_ts, $ignore, &$ignore_kicked)
145 170 { {
146 171 global $rg_sql_debug; global $rg_sql_debug;
147 172
173 $ignore_kicked = FALSE;
148 174 while (1) { while (1) {
175 if ($r !== TRUE) {
176 $err = "$sql: send: " . @pg_last_error($db);
177 $res = FALSE;
178 break;
179 }
180
181 $res = @pg_get_result($db);
149 182 if ($res === FALSE) { if ($res === FALSE) {
150 $err = "$sql: " . @pg_last_error($db);
151 rg_sql_set_error($err);
152 rg_internal_error($err);
153 rg_prof_set(array('qerrors' => 1));
154 // reconnect if needed
155 @pg_ping($db);
183 $err = $sql . ': get: no pending query';
156 184 break; break;
157 185 } }
158 186
159 $diff = sprintf("%u", (microtime(TRUE) - $_s) * 1000);
187 $state = rg_sql_last_error_code($res);
188 if ($state === FALSE) {
189 $err = $sql . ': get: pg_result_error_field error';
190 break;
191 }
192 if (($state !== NULL) && (strcmp($state, '00000') !== 0)) {
193 foreach ($ignore as $code) {
194 if (strcmp($code, $state) == 0) {
195 $ignore_kicked = TRUE;
196 break;
197 }
198 }
199
200 if ($ignore_kicked)
201 if ($rg_sql_debug > 50)
202 rg_log('DB: We should ignore the error!');
203
204 $err = $sql . ': ' . @pg_last_error($db) . ' (' . $state . ')';
205 @pg_free_result($res);
206 $res = FALSE;
207 break;
208 }
209
210 $diff = sprintf("%u", (microtime(TRUE) - $start_ts) * 1000);
160 211 $rows = rg_sql_num_rows($res); $rows = rg_sql_num_rows($res);
161 212 if ($rows == 0) if ($rows == 0)
162 213 $arows = rg_sql_affected_rows($res); $arows = rg_sql_affected_rows($res);
 
... ... function rg_sql_query0($db, $sql, $res, $_s)
173 224 break; break;
174 225 } }
175 226
227 if ($res === FALSE) {
228 rg_sql_set_error($err);
229 if (!$ignore_kicked) {
230 rg_internal_error($err);
231 rg_prof_set(array('qerrors' => 1));
232 }
233 // reconnect if needed
234 @pg_ping($db);
235 }
236
176 237 return $res; return $res;
177 238
178 239 } }
 
... ... function rg_sql_query($h, $sql)
193 254 if ($db === FALSE) if ($db === FALSE)
194 255 break; break;
195 256
196 $_s = microtime(TRUE);
197 $res = @pg_query($db, $sql);
198 $ret = rg_sql_query0($db, $sql, $res, $_s);
257 $ignore = array();
258 $start_ts = microtime(TRUE);
259 $r = @pg_send_query($db, $sql);
260 $ret = rg_sql_query0($db, $sql, $r, $start_ts,
261 $ignore, $ignore_kicked);
199 262 break; break;
200 263 } }
201 264
 
... ... function rg_sql_query($h, $sql)
207 270 /* /*
208 271 * Queries using params * Queries using params
209 272 * @params - array of fields -> values * @params - array of fields -> values
273 * @ignore - array of strings with errors we should not log as internal errors
274 * See https://www.postgresql.org/docs/current/static/errcodes-appendix.html
275 * @ignore_kicked will be set to true if the error is in @ignore array
210 276 * Examples: $params = array("id" => "1", "name" = "bau") * Examples: $params = array("id" => "1", "name" = "bau")
211 277 * $sql = "UPDATE x SET name = @@name@@ WHERE id = @@id@@ AND @@name@@ = @@name@@" * $sql = "UPDATE x SET name = @@name@@ WHERE id = @@id@@ AND @@name@@ = @@name@@"
212 * $sql2 = "UPDATE x SET name = $1 WHERE id = $2 AND name = $1"
278 * => $sql2 = "UPDATE x SET name = $1 WHERE id = $2 AND name = $1"
213 279 */ */
214 function rg_sql_query_params($h, $sql, $params)
280 function rg_sql_query_params_ignore($h, $sql, $params, $ignore, &$ignore_kicked)
215 281 { {
216 282 global $rg_sql_debug; global $rg_sql_debug;
217 283
218 284 if ($rg_sql_debug > 0) if ($rg_sql_debug > 0)
219 rg_log_enter("query_params: running [$sql] with [" . rg_array2string($params) . "]");
285 rg_log_enter('sql_query_params: sql=[' . $sql . ']'
286 . ' params=[' . rg_array2string($params) . ']'
287 . ' ignore=' . implode(',', $ignore));
220 288
221 289 $ret = FALSE; $ret = FALSE;
222 290 while (1) { while (1) {
 
... ... function rg_sql_query_params($h, $sql, $params)
241 309 //rg_log("new sql: $sql"); //rg_log("new sql: $sql");
242 310 //rg_log("params2: " . rg_array2string($params2)); //rg_log("params2: " . rg_array2string($params2));
243 311
244 $_s = microtime(TRUE);
245 $res = @pg_query_params($db, $sql, $params2);
246 $ret = rg_sql_query0($db, $sql, $res, $_s);
312 $start_ts = microtime(TRUE);
313 $r = @pg_send_query_params($db, $sql, $params2);
314 $ret = rg_sql_query0($db, $sql, $r, $start_ts, $ignore, $ignore_kicked);
247 315 break; break;
248 316 } }
249 317
 
... ... function rg_sql_query_params($h, $sql, $params)
252 320 return $ret; return $ret;
253 321 } }
254 322
323 function rg_sql_query_params($h, $sql, $params)
324 {
325 $ignore = array();
326 return rg_sql_query_params_ignore($h, $sql, $params,
327 $ignore, $ignore_kicked);
328 }
329
255 330 /* /*
256 331 * Close database * Close database
257 332 */ */
258 333 function rg_sql_close($h) function rg_sql_close($h)
259 334 { {
260 // TODO: why should I connect before close?!
261 $db = rg_sql_open_nodelay($h);
262 if ($db === FALSE)
335 global $rg_sql_conn;
336
337 if (!isset($rg_sql_conn[$h])) {
338 rg_internal_error('Handler ' . $h . ' was not allocated!');
263 339 return FALSE; return FALSE;
340 }
341
342 if (!isset($rg_sql_conn[$h]['db'])) {
343 // was not opened
344 return TRUE;
345 }
264 346
265 return pg_close($db);
347 $r = pg_close($rg_sql_conn[$h]['db']);
348 if ($r === FALSE)
349 return FALSE;
350
351 unset($rg_sql_conn[$h]['db']);
352
353 return TRUE;
266 354 } }
267 355
268 356 /* /*
 
... ... function rg_sql_rollback($h)
357 445 * Test if a table exists * Test if a table exists
358 446 * Returns FALSE on error, 0 if does not exists, 1 if exists * Returns FALSE on error, 0 if does not exists, 1 if exists
359 447 */ */
360 function rg_sql_rel_exists($db, $rel)
448 function rg_sql_rel_exists($h, $rel)
361 449 { {
362 450 $sql = "SELECT 1 FROM pg_class" $sql = "SELECT 1 FROM pg_class"
363 451 . " WHERE relname = '" . $rel . "'"; . " WHERE relname = '" . $rel . "'";
364 $res = rg_sql_query($db, $sql);
452 $res = rg_sql_query($h, $sql);
365 453 if ($res === FALSE) if ($res === FALSE)
366 454 return FALSE; return FALSE;
367 455
 
... ... function rg_sql_rel_exists($db, $rel)
374 462 /* /*
375 463 * Returns the fileds names of a table * Returns the fileds names of a table
376 464 */ */
377 function rg_sql_fields($db, $table)
465 function rg_sql_fields($h, $table)
378 466 { {
379 467 $params = array('table' => $table); $params = array('table' => $table);
380 468 $sql = 'SELECT column_name FROM information_schema.columns' $sql = 'SELECT column_name FROM information_schema.columns'
381 469 . ' WHERE table_name = @@table@@'; . ' WHERE table_name = @@table@@';
382 $res = rg_sql_query_params($db, $sql, $params);
470 $res = rg_sql_query_params($h, $sql, $params);
383 471 if ($res === FALSE) if ($res === FALSE)
384 472 return FALSE; return FALSE;
385 473
 
... ... function rg_sql_fields($db, $table)
393 481 return $ret; return $ret;
394 482 } }
395 483
484 /*
485 * Returns the last error codes
486 */
487 function rg_sql_last_error_code($res)
488 {
489 return @pg_result_error_field($res, PGSQL_DIAG_SQLSTATE);
490 }
491
396 492 ?> ?>
File inc/ssh.inc.php changed (mode: 100644) (index 3e530d8..b37fced)
... ... function rg_ssh_api($db, $ip, $uid, $paras)
338 338 foreach ($paras as $t) { foreach ($paras as $t) {
339 339 $v = explode('=', $t, 2); $v = explode('=', $t, 2);
340 340 if (count($v) != 2) { if (count($v) != 2) {
341 $a['error'] = 'invalid para (no =)';
341 $a['errmsg'] = 'invalid para (no =)';
342 342 $ret = json_encode($a, JSON_PRETTY_PRINT) . "\n"; $ret = json_encode($a, JSON_PRETTY_PRINT) . "\n";
343 343 break; break;
344 344 } }
 
... ... function rg_ssh_api($db, $ip, $uid, $paras)
346 346 $k = trim($v[0]); $k = trim($v[0]);
347 347 $a[$k] = trim($v[1]); $a[$k] = trim($v[1]);
348 348 } }
349 if (isset($a['error']))
349 if (isset($a['errmsg']))
350 350 break; break;
351 351
352 352 $a['cmd'] = $cmd; $a['cmd'] = $cmd;
File inc/struct.inc.php changed (mode: 100644) (index ff2201f..12ece8d)
... ... $rg_sql_struct[43]['other'] = array(
598 598 "ALTER TABLE commit_labels ADD itime INTEGER NOT NULL DEFAULT 0" "ALTER TABLE commit_labels ADD itime INTEGER NOT NULL DEFAULT 0"
599 599 ); );
600 600
601 $rg_sql_struct[44]['table'] = array(
602 'ldap_servers' =>
603 "CREATE TABLE ldap_servers"
604 . " (id SERIAL PRIMARY KEY"
605 . ", prio INTEGER NOT NULL"
606 . ", session_time INTEGER NOT NULL"
607 . ", itime INTEGER NOT NULL"
608 . ", who INTEGER NOT NULL"
609 . ", name TEXT NOT NULL"
610 . ", url TEXT NOT NULL"
611 . ", bind_dn TEXT NOT NULL"
612 . ", bind_pass TEXT NOT NULL"
613 . ", user_base TEXT NOT NULL"
614 . ", uid_attr TEXT NOT NULL"
615 . ", filter TEXT NOT NULL"
616 . ", group_base TEXT NOT NULL"
617 . ", group_attr TEXT NOT NULL"
618 . ", group_filter TEXT NOT NULL"
619 . ", admin_group TEXT NOT NULL"
620 . ", ca_cert TEXT NOT NULL"
621 . ", csn TEXT NOT NULL DEFAULT ''"
622 . ", plan_id INTEGER NOT NULL"
623 . ")",
624 'ldap_cache' =>
625 "CREATE TABLE ldap_cache"
626 . " (ldap_uid TEXT NOT NULL"
627 . ", password TEXT NOT NULL"
628 . ", sn TEXT NOT NULL"
629 . ", gn TEXT NOT NULL"
630 . ", gid INTEGER NOT NULL"
631 . ", mail TEXT NOT NULL"
632 . ", server_id INTEGER NOT NULL"
633 . ", uuid TEXT NOT NULL"
634 . ", uid INTEGER NOT NULL"
635 . ", cn TEXT NOT NULL"
636 . ", shadow_expire INTEGER NOT NULL"
637 . ", uid_number INTEGER NOT NULL"
638 . ", prio INTEGER NOT NULL"
639 . ")"
640 );
641 $rg_sql_struct[44]['other'] = array(
642 'index ldap_cache uuid' =>
643 "CREATE INDEX ldap_cache_i_uuid on ldap_cache(uuid)"
644 );
645
601 646 // Do not forget to add the new tables to statistics // Do not forget to add the new tables to statistics
602 647 // This must be the last line // This must be the last line
603 648 $rg_sql_schema_ver = count($rg_sql_struct); $rg_sql_schema_ver = count($rg_sql_struct);
 
... ... function rg_sql_struct_run($db, $flags, $old_schema_ver)
627 672 continue; continue;
628 673
629 674 foreach ($sqls as $id => $sql) { foreach ($sqls as $id => $sql) {
630 rg_log("Applying schema $i, type $type, id $id...");
675 rg_log("Applying schema '$i', type '$type', id '$id'...");
631 676
632 677 if ((strcmp($type, "tables") == 0) if ((strcmp($type, "tables") == 0)
633 678 && ($drop_tables === TRUE)) { && ($drop_tables === TRUE)) {
File inc/token.inc.php changed (mode: 100644) (index 5b0417d..6a99b70)
... ... function rg_token_valid($db, $rg, $tag, $double_allowed)
130 130
131 131 $hash = substr($hash, 0, 16); $hash = substr($hash, 0, 16);
132 132 if (strcmp($sign, $hash) != 0) { if (strcmp($sign, $hash) != 0) {
133 rg_log("DEBUG: sign=$sign != hash=$hash data=$data");
133 rg_log("DEBUG: substr(token, 16, 16)=$sign != hash_hmac(data,key)=$hash data=$data");
134 134 rg_token_set_error("token invalid"); rg_token_set_error("token invalid");
135 135 rg_security_violation_no_exit("invalid token (sign)"); rg_security_violation_no_exit("invalid token (sign)");
136 136 break; break;
 
... ... function rg_token_get($db, $rg, $tag)
243 243 rg_log('DEBUG: generated token ' . $ret); rg_log('DEBUG: generated token ' . $ret);
244 244 $ret2 = $ret; $ret2 = $ret;
245 245
246 if ($rg['debug']) {
246 if ($rg['debug'])
247 247 $ret2 .= ':' . $tag; $ret2 .= ':' . $tag;
248 rg_log('DEBUG" debug is active');
249 }
250 248
251 249 rg_cache_set($key, $ret2, RG_SOCKET_NO_WAIT); rg_cache_set($key, $ret2, RG_SOCKET_NO_WAIT);
252 250
File inc/user.inc.php changed (mode: 100644) (index 33db3df..e6d0a73)
... ... function rg_user_error()
44 44 */ */
45 45 $rg_user_functions = array( $rg_user_functions = array(
46 46 2000 => "rg_user_event_new", 2000 => "rg_user_event_new",
47 'user_event_new' => 'rg_user_event_new',
47 48 2001 => "rg_user_event_login", 2001 => "rg_user_event_login",
49 'user_event_login' => "rg_user_event_login",
48 50 2002 => "rg_user_event_notify_user", 2002 => "rg_user_event_notify_user",
49 51 2005 => "rg_user_event_rename", 2005 => "rg_user_event_rename",
50 52 2006 => "rg_user_link_by_name", 2006 => "rg_user_link_by_name",
 
... ... function rg_user_insert_rename($db, $uid, $old_name)
392 394 . " (" . rg_sql_error() . ")"); . " (" . rg_sql_error() . ")");
393 395 break; break;
394 396 } }
397 rg_sql_free_result($res);
395 398
396 399 rg_cache_set("old_name::" . $old_name, $uid, RG_SOCKET_NO_WAIT); rg_cache_set("old_name::" . $old_name, $uid, RG_SOCKET_NO_WAIT);
397 400
 
... ... function rg_user_rename($db, $ui, $new_name)
492 495 } }
493 496
494 497 /* /*
495 * Add/edit a user
496 * If uid > 0 - edit, else, add
498 * Helper for rg_user_edit
497 499 */ */
498 function rg_user_edit($db, $d)
500 function rg_user_edit_no_check($db, $d)
499 501 { {
500 rg_prof_start("user_edit");
501 rg_log_enter("user_edit: d: " . rg_array2string($d));
502 rg_prof_start('user_edit_no_check');
503 rg_log_enter('user_edit_no_check: d: ' . rg_array2string($d));
502 504
503 $ret = FALSE;
505 $ret = array('ok' => 0, 'already_exists' => 0);
504 506 while (1) { while (1) {
505 507 $add = $d['uid'] == 0; $add = $d['uid'] == 0;
506 508
507 if (rg_user_ok($d['username']) !== TRUE)
508 break;
509
510 // TODO: check rights
511 // TODO - check if user is allowed to give passed rights
512
513 if ($d['ask_for_email_confirmation'] == 1)
514 $d['confirmed'] = 0;
515
516 $update_pass = !empty($d['pass']);
509 $update_pass = $add || !empty($d['pass']);
517 510 if ($update_pass) { if ($update_pass) {
518 511 if (strcmp($d['pass'], $d['pass2']) != 0) { if (strcmp($d['pass'], $d['pass2']) != 0) {
519 rg_user_set_error("passwords are not the same");
512 $ret['errmsg'] = 'passwords are not the same';
513 break;
514 }
515
516 if (rg_user_pass_ok($d['pass']) !== TRUE) {
517 $ret['errmsg'] = rg_user_error();
520 518 break; break;
521 519 } }
522 520
 
... ... function rg_user_edit($db, $d)
524 522 $d['pass_crypted'] = rg_user_pass($d['salt'], $d['pass']); $d['pass_crypted'] = rg_user_pass($d['salt'], $d['pass']);
525 523 } }
526 524
527 $d['itime'] = time();
525 // No need to keep them in memory
526 unset($d['pass']);
527 unset($d['pass2']);
528 528
529 529 if ($add) { if ($add) {
530 if (rg_user_pass_ok($d['pass']) !== TRUE)
531 break;
532
533 $d['suspended'] = 0;
530 $d['itime'] = time();
531 if (!isset($d['suspended']))
532 $d['suspended'] = 0;
534 533 $d['deleted'] = 0; $d['deleted'] = 0;
535 534 $d['last_seen'] = 0; $d['last_seen'] = 0;
536 535 $d['disk_used_mb'] = 0; $d['disk_used_mb'] = 0;
537 $sql = "INSERT INTO users (username, realname, salt"
538 . ", pass, email, itime"
539 . ", is_admin, rights, session_time"
540 . ", confirmed, confirm_token, plan_id"
541 . ", suspended, last_seen, disk_used_mb"
542 . ", deleted)"
543 . " VALUES (@@username@@, @@realname@@, @@salt@@"
544 . ", @@pass_crypted@@, @@email@@, @@itime@@"
545 . ", @@is_admin@@, @@rights@@, @@session_time@@"
546 . ", @@confirmed@@, @@confirm_token@@, @@plan_id@@"
547 . ", @@suspended@@, @@last_seen@@"
548 . ", @@disk_used_mb@@, @@deleted@@)"
549 . " RETURNING uid";
536 $sql = 'INSERT INTO users (username, realname, salt'
537 . ', pass, email, itime'
538 . ', is_admin, rights, session_time'
539 . ', confirmed, confirm_token, plan_id'
540 . ', suspended, last_seen, disk_used_mb'
541 . ', deleted)'
542 . ' VALUES (@@username@@, @@realname@@, @@salt@@'
543 . ', @@pass_crypted@@, @@email@@, @@itime@@'
544 . ', @@is_admin@@, @@rights@@, @@session_time@@'
545 . ', @@confirmed@@, @@confirm_token@@, @@plan_id@@'
546 . ', @@suspended@@, @@last_seen@@'
547 . ', @@disk_used_mb@@, @@deleted@@'
548 . ')'
549 . ' RETURNING uid';
550
551 $ignore = array(RG_SQL_UNIQUE_VIOLATION);
550 552 } else { // edit } else { // edit
551 553 $salt_pass_add = ""; $salt_pass_add = "";
552 554 if ($update_pass) if ($update_pass)
553 $salt_pass_add = ", pass = @@pass_crypted@@"
554 . ", salt = @@salt@@";
555
556 $sql = "UPDATE users"
557 . " SET username = @@username@@"
558 . ", realname = @@realname@@"
559 . ", email = @@email@@"
560 . ", is_admin = @@is_admin@@"
561 . ", rights = @@rights@@"
562 . ", session_time = @@session_time@@"
563 . ", plan_id = @@plan_id@@"
564 . ", confirmed = @@confirmed@@"
565 . ", confirm_token = @@confirm_token@@"
555 $salt_pass_add = ', pass = @@pass_crypted@@'
556 . ', salt = @@salt@@';
557
558 $sql = 'UPDATE users'
559 . ' SET username = @@username@@'
560 . ', realname = @@realname@@'
561 . ', email = @@email@@'
562 . ', is_admin = @@is_admin@@'
563 . ', rights = @@rights@@'
564 . ', session_time = @@session_time@@'
565 . ', plan_id = @@plan_id@@'
566 . ', confirmed = @@confirmed@@'
567 . ', confirm_token = @@confirm_token@@'
566 568 . $salt_pass_add . $salt_pass_add
567 . " WHERE uid = @@uid@@";
569 . ' WHERE uid = @@uid@@';
570
571 $ignore = array();
568 572 } }
569 573
570 $res = rg_sql_query_params($db, $sql, $d);
574 $res = rg_sql_query_params_ignore($db, $sql, $d,
575 $ignore, $ignore_kicked);
571 576 if ($res === FALSE) { if ($res === FALSE) {
572 rg_user_set_error('cannot insert/update user info');
577 if (!$ignore_kicked) {
578 $ret['errmsg'] = 'cannot insert/update user info';
579 break;
580 }
581 rg_log('DEBUG: username already present');
582 $ret['already_exists'] = 1;
573 583 break; break;
574 584 } }
575 585 if ($add) { if ($add) {
 
... ... function rg_user_edit($db, $d)
583 593 $d, RG_SOCKET_NO_WAIT); $d, RG_SOCKET_NO_WAIT);
584 594
585 595 // we need to be able to send the welcome mail // we need to be able to send the welcome mail
586 $d['ignore_confirmed'] = 1;
596 $d2 = $d;
597 $d2['ignore_confirmed'] = 1;
587 598
588 599 $event = array( $event = array(
589 'category' => 2000,
600 'category' => 'user_event_new',
590 601 'prio' => 50, 'prio' => 50,
591 'ui' => $d,
602 'ui' => $d2,
592 603 'base_url' => rg_base_url() 'base_url' => rg_base_url()
593 604 ); );
594 605 $r = rg_event_add($db, $event); $r = rg_event_add($db, $event);
595 606 if ($r === FALSE) { if ($r === FALSE) {
596 rg_user_set_error('cannot add event');
607 $ret['errmsg'] = 'cannot add event';
597 608 break; break;
598 609 } }
599 rg_event_signal_daemon("", 0);
610 rg_event_signal_daemon('', 0);
600 611 } else { // edit } else { // edit
601 // else, we will overwrite the pass in cache
602 if (!$update_pass)
603 unset($d['pass']);
604 unset($d['pass2']); // not needed in cache
605 612 rg_cache_merge('user' . '::' . $d['uid'] rg_cache_merge('user' . '::' . $d['uid']
606 613 . '::' . 'info', $d, RG_SOCKET_NO_WAIT); . '::' . 'info', $d, RG_SOCKET_NO_WAIT);
607 614
608 if ($d['ask_for_email_confirmation'] == 1) {
615 if (isset($d['ask_for_email_confirmation'])
616 && ($d['ask_for_email_confirmation'] == 1)) {
609 617 $r = rg_user_ask_for_email_confirmation($db, $d['uid']); $r = rg_user_ask_for_email_confirmation($db, $d['uid']);
610 618 if ($r === FALSE) { if ($r === FALSE) {
611 rg_user_set_error('cannot add event');
619 $ret['errmsg'] = 'cannot add event';
612 620 break; break;
613 621 } }
614 622 } }
 
... ... function rg_user_edit($db, $d)
616 624
617 625 // TODO: should we cache here the user_by_uid and user_by_name // TODO: should we cache here the user_by_uid and user_by_name
618 626
619 $ret = $d['uid'];
627 $ret['ui'] = $d;
628 $ret['ok'] = 1;
629 break;
630 }
631
632 rg_log_exit();
633 rg_prof_end('user_edit_no_check');
634 return $ret;
635 }
636
637 /*
638 * Add/edit a user
639 * If uid > 0 - edit, else, add
640 */
641 function rg_user_edit($db, $d)
642 {
643 rg_prof_start("user_edit");
644 rg_log_enter("user_edit: d: " . rg_array2string($d));
645
646 $ret = FALSE;
647 while (1) {
648 if (rg_user_ok($d['username']) !== TRUE)
649 break;
650
651 // TODO: check rights
652 // TODO - check if user is allowed to give passed rights
653
654 if (isset($d['ask_for_email_confirmation'])
655 && ($d['ask_for_email_confirmation'] == 1))
656 $d['confirmed'] = 0;
657
658 $r = rg_user_edit_no_check($db, $d);
659 if ($r['ok'] !== 1) {
660 rg_user_set_error($r['errmsg']);
661 break;
662 }
663
664 $ret = $r['ui']['uid'];
620 665 break; break;
621 666 } }
622 667
 
... ... function rg_user_auto_login($db, $uid, $lock_ip, $domain, &$ui)
943 988 } }
944 989
945 990 /* /*
946 * Test if login is OK
991 * Helper for rg_user_login_by_user_pass for db
947 992 */ */
948 function rg_user_login_by_user_pass($db, $user, $pass, $login_token, $lock_ip,
949 $domain, &$ui)
993 function rg_user_login_by_user_pass_db($db, $user, $pass, $login_token,
994 $lock_ip, $domain, &$ui)
950 995 { {
951 996 global $rg_account_email_confirm; global $rg_account_email_confirm;
952 997
953 rg_prof_start('user_login_by_user_pass');
954 rg_log_enter('user_login_by_user_pass: user=' . $user
998 rg_prof_start('user_login_by_user_pass_db');
999 rg_log_enter('user_login_by_user_pass_db: user=' . $user
955 1000 . ' login_token=' . $login_token . ' lock_ip=' . $lock_ip . ' login_token=' . $login_token . ' lock_ip=' . $lock_ip
956 1001 . ' domain=' . $domain); . ' domain=' . $domain);
957 1002
 
... ... function rg_user_login_by_user_pass($db, $user, $pass, $login_token, $lock_ip,
959 1004
960 1005 $ret = FALSE; $ret = FALSE;
961 1006 while (1) { while (1) {
962 if (empty($user) || empty($pass)) {
963 rg_user_set_error("invalid user, pass or login token");
964 rg_log("user or pass are empty");
965 break;
966 }
967
968 1007 $ui0 = rg_user_info($db, 0, $user, ""); $ui0 = rg_user_info($db, 0, $user, "");
969 1008 if ($ui0['ok'] != 1) if ($ui0['ok'] != 1)
970 1009 break; break;
971 1010 if ($ui0['exists'] != 1) { if ($ui0['exists'] != 1) {
972 rg_user_set_error("invalid user, pass or login token");
973 rg_log("user doesn't exists");
974 break;
975 }
976
977 if ($ui0['deleted'] > 0) {
978 1011 rg_user_set_error('invalid user, pass or login token'); rg_user_set_error('invalid user, pass or login token');
979 rg_log('account is deleted');
980 break;
981 }
982
983 if ($ui0['suspended'] > 0) {
984 rg_user_set_error("invalid user, pass or login token");
985 rg_log("account is suspended");
1012 rg_log('user doesn\'t exists');
986 1013 break; break;
987 1014 } }
988 1015
 
... ... function rg_user_login_by_user_pass($db, $user, $pass, $login_token, $lock_ip,
999 1026 break; break;
1000 1027 } }
1001 1028
1002 $vi = rg_totp_verify_any($db, $ui0['uid'], $login_token);
1029 $ui = $ui0;
1030 $ret = TRUE;
1031 break;
1032 }
1033
1034 rg_log_exit();
1035 rg_prof_end('user_login_by_user_pass_db');
1036 return $ret;
1037 }
1038
1039 /*
1040 * Authorize a user
1041 */
1042 function rg_user_login_by_user_pass($db, $user, $pass, $login_token,
1043 $lock_ip, $domain, &$ui)
1044 {
1045 global $rg_login_functions;
1046
1047 // TODO: what about $ui - for ldap will not have some elements.
1048 // Should we fake them?
1049
1050 rg_prof_start('user_login_by_user_pass');
1051 rg_log_enter('user_login_by_user_pass: user=' . $user
1052 . ' login_token=' . $login_token . ' lock_ip=' . $lock_ip
1053 . ' domain=' . $domain);
1054
1055 $ui = rg_user_empty();
1056
1057 $ret = array();
1058 $ret['ok'] = 0;
1059 while (1) {
1060 if (empty($user) || empty($pass)) {
1061 rg_log("user or pass are empty");
1062 $ret['errmsg'] = 'invalid user, pass or login token';
1063 break;
1064 }
1065
1066 while (1) {
1067 $r = rg_user_login_by_user_pass_db($db, $user, $pass,
1068 $login_token, $lock_ip, $domain, $ui);
1069 if ($r === TRUE)
1070 break;
1071
1072 $ret['errmsg'] = rg_user_error();
1073
1074 // Try external authentication
1075 foreach ($rg_login_functions as $funcs) {
1076 $r = $funcs['login']($db, $user, $pass, $ui);
1077 if ($r['ok'] === 1) {
1078 unset($ret['errmsg']);
1079 $post = $r['post'];
1080 break;
1081 }
1082 }
1083 if (isset($ret['errmsg']))
1084 break;
1085
1086 // We found a good user/pass combination
1087 rg_log_ml('DEBUG: post: ' . print_r($post, TRUE));
1088 rg_log_ml('DEBUG: ui returned by login callback: ' . print_r($ui, TRUE));
1089
1090 $check_for_changes = TRUE;
1091 if ($ui['uid'] == 0) {
1092 // User found, but not in 'users' table.
1093 // We update the table and call the callback
1094 // to set uid into external auth table.
1095
1096 rg_log('DEBUG: user not in \'users\' table (ui[uid] 0), add it');
1097 $r = rg_user_edit_no_check($db, $ui);
1098 if ($r['ok'] !== 1) {
1099 if ($r['already_exists'] == 0) {
1100 $ret['errmsg'] = $r['errmsg'];
1101 break;
1102 }
1103
1104 rg_log('DEBUG: user is already present'
1105 . '; lookup by username');
1106 $ui = rg_user_info($db, 0, $ui['username'], '');
1107 if ($ui['ok'] !== 1) {
1108 $ret['errmsg'] = rg_user_error();
1109 break;
1110 }
1111 } else {
1112 $ui['uid'] = $r['ui']['uid'];
1113 $check_for_changes = FALSE;
1114 }
1115
1116 // This will update external auth cache uid.
1117 if (isset($funcs['post_login'])) {
1118 $r = $funcs['post_login']($db,
1119 $ui['uid'], $post);
1120 // We will not return an error here
1121 if ($r['ok'] !== 1)
1122 rg_log('post_login function'
1123 . ' returned error: '
1124 . $r['errmsg']);
1125 }
1126 } else {
1127 // User found, but some fields may have old
1128 // values and we may need to update 'users'.
1129
1130 rg_log('DEBUG: user exists in db (ui[uid]!=0), load info');
1131 $ui = rg_user_info($db, $ui['uid'], '', '');
1132 if ($ui['ok'] !== 1) {
1133 $ret['errmsg'] = rg_user_error();
1134 break;
1135 }
1136 }
1137
1138 // Some fields could change
1139 $do_update = FALSE;
1140 while (1) {
1141 if (!$check_for_changes)
1142 break;
1143
1144 if (strcmp($ui['username'], $post['username']) != 0) {
1145 rg_log('DEBUG: different username: ' . $ui['username'] . ' != ' . $post['username']);
1146 $ui['username'] = $post['username'];
1147 $do_update = TRUE;
1148 break;
1149 }
1150
1151 if (strcmp($ui['email'], $post['mail']) != 0) {
1152 rg_log('DEBUG: different mail');
1153 $ui['email'] = $post['mail'];
1154 $do_update = TRUE;
1155 break;
1156 }
1157
1158 if (strcmp($ui['realname'], $post['realname']) != 0) {
1159 rg_log('DEBUG: different realname');
1160 $ui['realname'] = $post['realname'];
1161 $do_update = TRUE;
1162 break;
1163 }
1164
1165 if (strcmp($ui['pass'], $post['password']) != 0) {
1166 rg_log('DEBUG: different passwords');
1167 $ui['pass'] = $post['password'];
1168 $ui['pass2'] = $post['password'];
1169 $do_update = TRUE;
1170 break;
1171 }
1172
1173 // TODO: expiration?
1174 // TODO: plan_id will change when we will edit
1175 // the ldap server info. Same with is_admin.
1176 // Same with 'prio'.
1177
1178 break;
1179 }
1180 if ($do_update) {
1181 rg_log('DEBUG: desync between sql and ldap');
1182
1183 // If we do not have pass2, we do not want
1184 // to change the password.
1185 if (!isset($ui['pass2']))
1186 unset($ui['pass']);
1187
1188 $r = rg_user_edit_no_check($db, $ui);
1189 if ($r['ok'] !== 1) {
1190 $ret['errmsg'] = $r['errmsg'];
1191 break;
1192 }
1193 }
1194
1195 break;
1196 }
1197 if (isset($ret['errmsg']))
1198 break;
1199
1200 if ($ui['deleted'] > 0) {
1201 $ret['errmsg'] = 'invalid user, pass or login token';
1202 rg_log('account is deleted');
1203 break;
1204 }
1205
1206 if ($ui['suspended'] > 0) {
1207 $ret['errmsg'] = 'invalid user, pass or login token';
1208 rg_log('account is suspended');
1209 break;
1210 }
1211
1212 $vi = rg_totp_verify_any($db, $ui['uid'], $login_token);
1003 1213 if ($vi['ok'] != 1) { if ($vi['ok'] != 1) {
1004 rg_user_set_error('login token error: ' . rg_totp_error());
1214 $ret['errmsg'] = 'login token error: ' . rg_totp_error();
1005 1215 break; break;
1006 1216 } }
1007 1217 //rg_log_ml('DEBUG: vi: ' . print_r($vi, TRUE)); //rg_log_ml('DEBUG: vi: ' . print_r($vi, TRUE));
1008 1218 if (($vi['enrolled'] == 1) && ($vi['token_valid'] != 1)) { if (($vi['enrolled'] == 1) && ($vi['token_valid'] != 1)) {
1009 rg_user_set_error('invalid user, pass or login token');
1219 $ret['errmsg'] = 'invalid user, pass or login token';
1010 1220 rg_log('invalid token'); rg_log('invalid token');
1011 1221 break; break;
1012 1222 } }
1013 1223
1014 1224 $event = array( $event = array(
1015 'category' => 2001,
1225 'category' => 'user_event_login',
1016 1226 'prio' => 100, 'prio' => 100,
1017 'ui' => $ui0,
1227 'ui' => $ui,
1018 1228 'itime' => time()); 'itime' => time());
1019 1229 $r = rg_event_add($db, $event); $r = rg_event_add($db, $event);
1020 1230 if ($r !== TRUE) { if ($r !== TRUE) {
1021 rg_user_set_error('internal error; try again later');
1231 $ret['errmsg'] = 'internal error; try again later';
1022 1232 break; break;
1023 1233 } }
1024 1234 rg_event_signal_daemon('', 0); rg_event_signal_daemon('', 0);
1025 1235
1026 $ui = $ui0;
1027 1236 rg_user_auto_login($db, $ui['uid'], $lock_ip, $domain, $ui); rg_user_auto_login($db, $ui['uid'], $lock_ip, $domain, $ui);
1028 1237
1029 $ret = TRUE;
1238 $ret['ok'] = 1;
1030 1239 break; break;
1031 1240 } }
1032 1241
1033 1242 rg_log_exit(); rg_log_exit();
1034 rg_prof_start("user_login_by_user_pass");
1243 rg_prof_end('user_login_by_user_pass');
1035 1244 return $ret; return $ret;
1036 1245 } }
1037 1246
 
... ... function rg_user_edit_high_level($db, &$rg)
1649 1858 else else
1650 1859 $ui['tos'] = rg_var_uint('tos'); $ui['tos'] = rg_var_uint('tos');
1651 1860
1652 $ui['ask_for_email_confirmation'] = 0;
1653 1861 $ui['confirm_token'] = rg_id(20); $ui['confirm_token'] = rg_id(20);
1654 1862 if ($rg['target_ui']['uid'] > 0) { if ($rg['target_ui']['uid'] > 0) {
1655 1863 if (strcasecmp($rg['target_ui']['email'], $ui['email']) != 0) { if (strcasecmp($rg['target_ui']['email'], $ui['email']) != 0) {
 
... ... function rg_user_edit_high_level($db, &$rg)
1719 1927
1720 1928 if ($load_form) { if ($load_form) {
1721 1929 $rg = array_merge($rg, $ui); $rg = array_merge($rg, $ui);
1722 $rg['HTML:select_plan'] = rg_plan_select($db, $ui['plan_id']);
1930 $rg['HTML:select_plan'] = rg_plan_select($db, 'plan_id',
1931 $ui['plan_id']);
1723 1932 $rg['HTML:checkbox_rights'] = rg_rights_checkboxes("user", $rg['HTML:checkbox_rights'] = rg_rights_checkboxes("user",
1724 1933 "rights", $ui['rights']); "rights", $ui['rights']);
1725 1934 $rg['HTML:errmsg'] = rg_template_errmsg($errmsg); $rg['HTML:errmsg'] = rg_template_errmsg($errmsg);
 
... ... function rg_process_input($content_length, $content_encoding, &$err)
1897 2106 // TODO: Sadly, we are not able to do the streaming! // TODO: Sadly, we are not able to do the streaming!
1898 2107 // It is not available to php-fpm! // It is not available to php-fpm!
1899 2108
1900 rg_git_info_pack("\x02", 'We could not process'
1901 . ' the data (chunked).');
1902
2109 rg_git_info_pack("\x02", 'We could not process'
2110 . ' the data (chunked).');
1903 2111
1904 2112 $err = 'You are trying to push chunked encoding data' $err = 'You are trying to push chunked encoding data'
1905 2113 . ' but php-fpm does not support it.' . "\n" . ' but php-fpm does not support it.' . "\n"
 
... ... function rg_user_http_git($db, $rg, $paras)
2046 2254 $rg['login_ui'], $prefix, $user, $repo, $service); $rg['login_ui'], $prefix, $user, $repo, $service);
2047 2255 rg_log_ml('DEBUG: repo_fetch_push_helper: ' . print_r($r, TRUE)); rg_log_ml('DEBUG: repo_fetch_push_helper: ' . print_r($r, TRUE));
2048 2256 if ($r['ok'] !== 1) { if ($r['ok'] !== 1) {
2049 rg_log('DEBUG: set errror: ' . $r['error']);
2050 header('X-Rocketgit-Error: ' . $r['error']);
2257 rg_log('DEBUG: set errror: ' . $r['errmsg']);
2258 header('X-Rocketgit-Error: ' . $r['errmsg']);
2051 2259
2052 2260 if (isset($r['owner_ui'])) { if (isset($r['owner_ui'])) {
2053 2261 if ($r['owner_ui']['ok'] != 1) { if ($r['owner_ui']['ok'] != 1) {
 
... ... function rg_user_http_git($db, $rg, $paras)
2089 2297 . ' realm="Use empty user if you have no account"'); . ' realm="Use empty user if you have no account"');
2090 2298 echo 'RocketGit: Info: == Welcome to RocketGit! ==' . "\n"; echo 'RocketGit: Info: == Welcome to RocketGit! ==' . "\n";
2091 2299 echo 'RocketGit: Info: you are connecting from IP ' . $rg['ip'] . '.' . "\n"; echo 'RocketGit: Info: you are connecting from IP ' . $rg['ip'] . '.' . "\n";
2092 echo 'RocketGit: Error: ' . $r['error'] . '!';
2300 echo 'RocketGit: Error: ' . $r['errmsg'] . '!';
2093 2301 break; break;
2094 2302 } }
2095 2303
2096 2304 rg_log('DEBUG: push_allowed=' . $r['push_allowed'] rg_log('DEBUG: push_allowed=' . $r['push_allowed']
2097 2305 . ' empty_user=' . ($empty_user ? 'yes' : 'no') . ' empty_user=' . ($empty_user ? 'yes' : 'no')
2098 . ' authd=' . ($authd === TRUE ? 'yes' : 'no')
2306 . ' authd=' . ($authd['ok'] === 1 ? 'yes' : 'no')
2099 2307 . ' exists=' . $auth_ui['exists'] . ' exists=' . $auth_ui['exists']
2100 2308 . ' push=' . $r['push']); . ' push=' . $r['push']);
2101 2309 if (($r['push'] === 1) && ($r['push_allowed'] !== 1)) { if (($r['push'] === 1) && ($r['push_allowed'] !== 1)) {
 
... ... function rg_user_http_git($db, $rg, $paras)
2104 2312 // the user to try again. If user is not correct, // the user to try again. If user is not correct,
2105 2313 // we will go on with anon push access. // we will go on with anon push access.
2106 2314 if ($empty_user if ($empty_user
2107 || (($authd === FALSE) && ($auth_ui['exists'] == 1))) {
2315 || (($authd['ok'] !== 1) && ($auth_ui['exists'] == 1))) {
2108 2316 rg_log('DEBUG: send 401'); rg_log('DEBUG: send 401');
2109 2317 header($protocol . ' 401 Unauthorized status'); header($protocol . ' 401 Unauthorized status');
2110 2318 header('WWW-Authenticate: Basic' header('WWW-Authenticate: Basic'
File inc/util.inc.php changed (mode: 100644) (index 41d439d..70d954e)
... ... register_shutdown_function("rg_error_shutdown");
7 7
8 8 define('RG_SOCKET_NO_WAIT', 0x01); define('RG_SOCKET_NO_WAIT', 0x01);
9 9
10 if (!isset($rg_util_debug))
11 $rg_util_debug = FALSE;
12
10 13 $rg_util_error = ""; $rg_util_error = "";
11 14
12 15 function rg_util_set_error($str) function rg_util_set_error($str)
 
... ... function rg_exec($cmd, $input, $cb_stdout, $cb_stderr)
1189 1192 return $ret; return $ret;
1190 1193 } }
1191 1194
1195 /*
1196 * This will replace rg_exec function
1197 */
1198 function rg_exec2(&$a)
1199 {
1200 global $rg_util_debug;
1201
1202 rg_prof_start('exec2');
1203 rg_log_enter('exec2');
1204
1205 $rg_util_debug &&
1206 rg_log_ml('DEBUG: a: ' . print_r($a, TRUE));
1207
1208 // some status initialization
1209 $s = array();
1210 foreach ($a['cmds'] as $cmd => &$info) {
1211 if (!isset($info['restart_delay']))
1212 $info['restart_delay'] = 0;
1213 if (!isset($info['idle_time']))
1214 $info['idle_time'] = 5;
1215
1216 $info['needs_start'] = TRUE;
1217 $info['needs_stop'] = FALSE;
1218 $info['last_failure'] = 0;
1219 if (!isset($info['out_buf']))
1220 $info['out_buf'] = '';
1221 $info['in_buf'] = '';
1222 $info['err_buf'] = '';
1223 $info['done'] = FALSE;
1224 $info['last_activity'] = 0;
1225 $info['stopped'] = TRUE;
1226 $info['closed'] = array(1 => 0, 2 => 0);
1227 }
1228
1229 $ret = array();
1230 $ret['ok'] = 0;
1231 while (1) {
1232 // check if all commands are started
1233 $now = time();
1234 $rx = array(); $wx = array();
1235 $lut = array();
1236 $done = TRUE;
1237 foreach ($a['cmds'] as $index => &$info) {
1238 if (($info['closed'][1] == 1) && ($info['closed'][2] == 1)) {
1239 $rg_util_debug && rg_log('DEBUG: Both in streams are closed.');
1240 $info['needs_stop'] = TRUE;
1241 }
1242
1243 if ($info['needs_stop'] == TRUE) {
1244 $rg_util_debug &&
1245 rg_log('DEBUG: index ' . $index . ' needs stop!');
1246
1247 $info['ps'] = @proc_get_status($info['a']);
1248 $rg_util_debug &&
1249 rg_log_ml('DEBUG: info[ps][' . $index . ']: '
1250 . print_r($info['ps'], TRUE));
1251
1252 if ($info['ps']['running'] === FALSE) {
1253 $ec = $info['ps']['exitcode'];
1254 } else {
1255 for ($i = 0; $i < 3; $i++)
1256 if (isset($info['pipes'][$i]))
1257 fclose($info['pipes'][$i]);
1258
1259 $err = @proc_close($info['a']);
1260 if ($err != 0)
1261 $rg_util_debug &&
1262 rg_log('DEBUG: proc_close returned ' . $err);
1263 $ec = 0; /* we are force closing program */
1264 }
1265
1266 if (isset($info['cb_finish']))
1267 $info['cb_finish']($index, $info, $ec);
1268
1269 unset($info['pipes']);
1270 unset($info['a']);
1271
1272 $info['needs_stop'] = FALSE;
1273 $info['stopped'] = TRUE;
1274
1275 if (isset($info['restart_delay'])) {
1276 $rg_util_debug &&
1277 rg_log('DEBUG: index ' . $index . ' has no restart flag => done = TRUE');
1278 $info['done'] = TRUE;
1279 }
1280 }
1281
1282 $rg_util_debug &&
1283 rg_log('DEBUG: index=' . $index
1284 . ' done=' . ($info['done'] === TRUE ? 'true' : 'false'));
1285 if ($info['done'])
1286 continue;
1287
1288 $done = FALSE;
1289
1290 if ($info['needs_start'] == TRUE) {
1291 $done = FALSE;
1292
1293 if ($info['last_failure'] + $info['restart_delay'] > $now)
1294 continue;
1295
1296 $rg_util_debug &&
1297 rg_log('DEBUG: Running [' . $info['cmd'] . ']');
1298 $desc = array(
1299 0 => array("pipe", "r"),
1300 1 => array('pipe', 'w'),
1301 2 => array("pipe", "w")
1302 );
1303
1304 $info['a'] = proc_open($info['cmd'], $desc, $info['pipes']);
1305 if ($info['a'] === FALSE) {
1306 $info['last_errmsg'] = 'cannot do proc_open';
1307 if (isset($info['cb_error']))
1308 $info['cb_error']($index, $info, $info['last_errmsg']);
1309 $info['last_failure'] = $now;
1310 continue;
1311 }
1312
1313 $rg_util_debug &&
1314 rg_log_ml('DEBUG: proc_open pipes: '
1315 . print_r($info['pipes'], TRUE));
1316 $info['needs_start'] = FALSE;
1317 $info['start_ts'] = time();
1318 $info['stopped'] = FALSE;
1319 $info['last_errmsg'] = '';
1320 $info['closed'][1] = 0;
1321 $info['closed'][2] = 0;
1322 }
1323
1324 if ($info['stopped']) {
1325 $rg_util_debug &&
1326 rg_log('DEBUG: index ' . $index. ' is stopped');
1327 continue;
1328 }
1329
1330 // Check idle
1331 if (isset($info['cb_idle'])
1332 && ($info['idle_time'] > 0)
1333 && ($info['last_activity'] > 0)
1334 && ($info['last_activity'] + $info['idle_time'] <= time())) {
1335 $rg_util_debug &&
1336 rg_log('DEBUG: IDLE: ' . $index
1337 . ' last_activity=' . $info['last_activity']
1338 . ' now=' . time());
1339 $info['cb_idle']($index, $info);
1340 }
1341
1342 if ($info['closed'][1] == 0) $rx[] = $info['pipes'][1];
1343 if ($info['closed'][2] == 0) $rx[] = $info['pipes'][2];
1344
1345 if (isset($info['cb_output']) || !empty($info['out_buf'])) {
1346 $rg_util_debug &&
1347 rg_log('DEBUG: We have cb_output or data in out_buf, enable write notification!');
1348 $wx[] = $info['pipes'][0];
1349 }
1350
1351 for ($i = 0; $i <= 2; $i++) {
1352 $k = intval($info['pipes'][$i]);
1353 $lut[$k] = array('index' => $index, 'stream' => $i);
1354 }
1355 }
1356 if ($done) {
1357 $rg_util_debug &&
1358 rg_log('DEBUG: No work to do anymore! Exit!');
1359 $ret['ok'] = 1;
1360 break;
1361 }
1362
1363 if (empty($rx) && empty($wx)) {
1364 $rg_util_debug &&
1365 rg_log('DEBUG: No events... sleeping');
1366 sleep(1);
1367 continue;
1368 }
1369
1370 $revents = $rx;
1371 $wevents = $wx;
1372 $ex = NULL;
1373 $rg_util_debug && rg_log('DEBUG: before stream_select:');
1374 $rg_util_debug && !empty($revents) && rg_log_ml('revents: ' . trim(print_r($revents, TRUE)));
1375 $rg_util_debug && !empty($wevents) && rg_log_ml('wevents: ' . trim(print_r($wevents, TRUE)));
1376 $r = stream_select($revents, $wevents, $ex, 1, 0);
1377 if ($r === FALSE) {
1378 $ret['errmsg'] = "cannot select";
1379 break;
1380 }
1381
1382 if (isset($a['cb_tick']))
1383 $a['cb_tick']($a);
1384
1385 if ($r === 0)
1386 continue;
1387
1388 $rg_util_debug && rg_log('DEBUG: stream_select returned ' . $r . ' events.');
1389 $rg_util_debug && !empty($revents) && rg_log_ml('revents: ' . trim(print_r($revents, TRUE)));
1390 $rg_util_debug && !empty($wevents) && rg_log_ml('wevents: ' . trim(print_r($wevents, TRUE)));
1391 $rg_util_debug && !empty($ex) && rg_log_ml('ex: ' . trim(print_r($ex, TRUE)));
1392
1393 foreach ($wevents as $fd) {
1394 $ifd = intval($fd);
1395 $index = $lut[$ifd]['index'];
1396 $rg_util_debug &&
1397 rg_log('DEBUG: write event on ifd ' . $ifd
1398 . ' index=' . $index . '!');
1399
1400 $info = &$a['cmds'][$index];
1401
1402 $rg_util_debug &&
1403 rg_log('DEBUG: out_buf before cb: ' . $info['out_buf']);
1404
1405 // cb_output will populate $info['out_buf']
1406 if (isset($info['cb_output']))
1407 $info['cb_output']($index, $info);
1408
1409 if (empty($info['out_buf'])) {
1410 $rg_util_debug &&
1411 rg_log_ml('DEBUG: out_buf is empty!' . print_r($info, TRUE));
1412 continue;
1413 }
1414
1415 $rg_util_debug &&
1416 rg_log('DEBUG: SENDING: [' . $info['out_buf'] . ']');
1417 $r = @fwrite($fd, $info['out_buf']);
1418 if ($r === FALSE) {
1419 $info['last_errmsg'] = 'cannot write';
1420 if (isset($info['cb_error']))
1421 $info['cb_error']($index, $info, $info['last_errmsg']);
1422 $info['needs_stop'] = TRUE;
1423 continue;
1424 }
1425 $rg_util_debug &&
1426 rg_log('DEBUG: fwrite returned ' . $r . '.');
1427 $info['out_buf'] = substr($info['out_buf'], $r);
1428 }
1429
1430 foreach ($revents as $fd) {
1431 $ifd = intval($fd);
1432 $index = $lut[$ifd]['index'];
1433 $stream = $lut[$ifd]['stream'];
1434 $rg_util_debug &&
1435 rg_log('DEBUG: read event on ifd ' . $ifd
1436 . ' index=' . $index . ', stream=' . $stream . '!');
1437
1438 $info = &$a['cmds'][$index];
1439
1440 $_d = @fread($fd, 32 * 4096);
1441 if ($_d === FALSE) {
1442 $rg_util_debug &&
1443 rg_log('DEBUG: ifd ' . $ifd . ' fread returned FALSE');
1444 $info['last_errmsg'] = 'cannot read';
1445 if (isset($info['cb_error']))
1446 $info['cb_error']($index, $info, $info['last_errmsg']);
1447 $info['needs_stop'] = TRUE;
1448 continue;
1449 }
1450
1451 if (empty($_d)) {
1452 $rg_util_debug &&
1453 rg_log('DEBUG: ifd ' . $ifd . ' returned no data.');
1454 $info['closed'][$stream] = 1;
1455 continue;
1456 }
1457
1458 $info['last_activity'] = time();
1459 $rg_util_debug &&
1460 rg_log('DEBUG: index ' . $index . ': set last_activity to ' . $info['last_activity']);
1461
1462 switch ($stream) {
1463 case 1: $info['in_buf'] .= $_d; break;
1464 case 2: $info['err_buf'] .= $_d; break;
1465 }
1466
1467 if (isset($info['cb_input']))
1468 $info['cb_input']($index, $info, $stream);
1469 }
1470 }
1471
1472 rg_log_exit();
1473 rg_prof_end('exec2');
1474 return $ret;
1475 }
1476
1192 1477 /* /*
1193 1478 * Force browser to redirect to another page * Force browser to redirect to another page
1194 1479 */ */
 
... ... $rg_socket_cache = array();
1530 1815 */ */
1531 1816 function rg_socket_recv_wait($socket, $wait, $timeout) function rg_socket_recv_wait($socket, $wait, $timeout)
1532 1817 { {
1533 rg_prof_start('sock_recv_wait');
1534
1535 $ret = FALSE;
1818 rg_prof_start('socket_recv_wait');
1536 1819
1537 1820 if ($timeout === NULL) { if ($timeout === NULL) {
1538 1821 $tv_sec = NULL; $tv_sec = NULL;
 
... ... function rg_socket_recv_wait($socket, $wait, $timeout)
1543 1826 } }
1544 1827
1545 1828 $ret_buf = ''; $ret_buf = '';
1829 $ret = FALSE;
1546 1830 while (1) { while (1) {
1547 1831 $reads = array($socket); $writes = array(); $ex = array(); $reads = array($socket); $writes = array(); $ex = array();
1548 1832 $r = @socket_select($reads, $writes, $ex, $tv_sec, $tv_usec); $r = @socket_select($reads, $writes, $ex, $tv_sec, $tv_usec);
 
... ... function rg_socket_recv_wait($socket, $wait, $timeout)
1552 1836 } }
1553 1837
1554 1838 if ($r === 0) { // timeout if ($r === 0) { // timeout
1555 rg_log('Timeout in reading!');
1839 rg_log('Timeout reading from socket!');
1556 1840 break; break;
1557 1841 } }
1558 1842
 
... ... function rg_socket_recv_wait($socket, $wait, $timeout)
1578 1862 break; break;
1579 1863 } }
1580 1864
1581 rg_prof_end('sock_recv_wait');
1865 rg_prof_end('socket_recv_wait');
1582 1866 return $ret; return $ret;
1583 1867 } }
1584 1868
 
... ... function rg_echo($s)
1836 2120 echo $s; echo $s;
1837 2121 } }
1838 2122
2123 /*
2124 * Function used to register login functions
2125 */
2126 $rg_login_functions = array();
2127 function rg_register_login_function($f)
2128 {
2129 global $rg_login_functions;
2130
2131 $rg_login_functions[] = $f;
2132 }
2133
1839 2134 ?> ?>
File inc/wh/amazon.inc.php changed (mode: 100644) (index 749260e..1f566cf)
... ... function rg_amazon_curl($url, $method, $headers, $data)
141 141
142 142 $c = curl_init($url); $c = curl_init($url);
143 143 if ($c === FALSE) { if ($c === FALSE) {
144 $ret['error'] = 'cannot init curl';
144 $ret['errmsg'] = 'cannot init curl';
145 145 break; break;
146 146 } }
147 147
 
... ... function rg_amazon_curl($url, $method, $headers, $data)
177 177 } }
178 178
179 179 if ($r === FALSE) { if ($r === FALSE) {
180 $ret['error'] = curl_error($c);
180 $ret['errmsg'] = curl_error($c);
181 181
182 182 $_info = curl_getinfo($c); $_info = curl_getinfo($c);
183 183 rg_log_ml('Debug: ' . print_r($_info, TRUE)); rg_log_ml('Debug: ' . print_r($_info, TRUE));
 
... ... function rg_amazon_curl($url, $method, $headers, $data)
189 189
190 190 if (($_info['http_code'] != 200) if (($_info['http_code'] != 200)
191 191 && ($_info['http_code'] != 301)) { && ($_info['http_code'] != 301)) {
192 $ret['error'] = $r;
192 $ret['errmsg'] = $r;
193 193 break; break;
194 194 } }
195 195
 
... ... function rg_amazon_req($a)
238 238
239 239 $auth = rg_amazon_auth($a); $auth = rg_amazon_auth($a);
240 240 if ($auth['ok'] != 1) { if ($auth['ok'] != 1) {
241 $ret['error'] = $auth['error'];
241 $ret['errmsg'] = $auth['error'];
242 242 break; break;
243 243 } }
244 244
File inc/wh/build.inc.php changed (mode: 100644) (index 6a7af81..efe0a95)
... ... function rg_wh_build_send_one($db, $event)
72 72
73 73 $ri = rg_repo_info($db, $event['ri']['repo_id'], 0, ''); $ri = rg_repo_info($db, $event['ri']['repo_id'], 0, '');
74 74 if ($ri['ok'] != 1) { if ($ri['ok'] != 1) {
75 $last_output .= $ri['error'];
75 $last_output .= $ri['errmsg'];
76 76 break; break;
77 77 } }
78 78
 
... ... function rg_wh_build_send_one($db, $event)
89 89 // Call the function // Call the function
90 90 $r = rg_builder_add($db, $event['ri']['repo_id'], $a); $r = rg_builder_add($db, $event['ri']['repo_id'], $a);
91 91 if ($r['ok'] != 1) { if ($r['ok'] != 1) {
92 $last_output .= $r['error'];
92 $last_output .= $r['errmsg'];
93 93 break; break;
94 94 } }
95 95
File inc/wh/cloud.inc.php changed (mode: 100644) (index a27ff4b..4fc6f0d)
... ... function rg_wh_cloud_send_one($db, $event)
57 57 } }
58 58 $r = rg_amazon_s3_put_object($wh['idata'], $c); $r = rg_amazon_s3_put_object($wh['idata'], $c);
59 59 if ($r['ok'] != 1) { if ($r['ok'] != 1) {
60 $last_output .= $r['error'];
60 $last_output .= $r['errmsg'];
61 61 break; break;
62 62 } }
63 63 $last_output .= $r['answer']; $last_output .= $r['answer'];
 
... ... function rg_wh_cloud_send_one($db, $event)
67 67 // Do the code deploy // Do the code deploy
68 68 $r = rg_amazon_codedeploy_create($wh['idata']); $r = rg_amazon_codedeploy_create($wh['idata']);
69 69 if ($r['ok'] != 1) { if ($r['ok'] != 1) {
70 $last_output .= $r['error'];
70 $last_output .= $r['errmsg'];
71 71 break; break;
72 72 } }
73 73
File inc/wh/lambda.inc.php changed (mode: 100644) (index 0452b33..3e24827)
... ... function rg_wh_lambda_send_one($db, $event)
37 37 // Call the function // Call the function
38 38 $r = rg_amazon_lambda_invoke($wh['idata']); $r = rg_amazon_lambda_invoke($wh['idata']);
39 39 if ($r['ok'] != 1) { if ($r['ok'] != 1) {
40 $last_output .= $r['error'];
40 $last_output .= $r['errmsg'];
41 41 break; break;
42 42 } }
43 43
File root/index.php changed (mode: 100644) (index 1fdd68f..449892b)
... ... include_once($INC . "/api.inc.php");
27 27 include_once($INC . "/apikeys.inc.php"); include_once($INC . "/apikeys.inc.php");
28 28 include_once($INC . "/demo.inc.php"); include_once($INC . "/demo.inc.php");
29 29 include_once($INC . "/ver.php"); include_once($INC . "/ver.php");
30 include_once($INC . "/ldap.inc.php");
30 31
31 32 rg_prof_start("MAIN"); rg_prof_start("MAIN");
32 33
File root/themes/default/admin/ldap/add_edit.html added (mode: 100644) (index 0000000..39ebca2)
1 <div class="formarea">
2
3 <div class="formarea_title">@@if(@@ldap::id@@ == 0){{Add a new LDAP server}}{{Edit a LDAP server}}</div>
4
5 @@errmsg@@
6
7 <form method="post" action="/op/admin/settings/add">
8 <input type="hidden" name="ldap::id" value="@@ldap::id@@" />
9 <input type="hidden" name="doit" value="1" />
10 <input type="hidden" name="token" value="@@rg_form_token@@" />
11
12 <p>
13 <label for="name">Name of the server</label><br />
14 <input type="text" name="ldap::name" id="name" value="@@ldap::name@@" />
15 </p>
16
17 <p>
18 <label for="plan_id">Plan</label><br />
19 @@select_plan@@
20 </p>
21
22 <p>
23 <label for="prio">Priority (bigger number less priority)</label><br />
24 <input type="text" name="ldap::prio" id="prio" value="@@ldap::prio@@" />
25 </p>
26
27 <p>
28 <label for="session_time">Session time</label><br />
29 <input type="text" name="ldap::session_time" id="session_time" value="@@ldap::session_time@@" />
30 </p>
31
32 <p>
33 <label for="url">URLs (space separated; example: ldaps://ldap.example.org ldaps://backup.example.org)</label><br />
34 <input type="text" name="ldap::url" id="url" value="@@ldap::url@@" />
35 </p>
36
37 <p>
38 <label for="bind_dn">Bind DN (optional; example: cn=anon,dc=example,dc=org)</label><br />
39 <input type="text" name="ldap::bind_dn" id="bind_dn" value="@@ldap::bind_dn@@" />
40 </p>
41
42 <p>
43 <label for="bind_pass">Bind password (optional)</label><br />
44 <input type="password" name="ldap::bind_pass" id="bind_pass" value="@@ldap::bind_pass@@" />
45 </p>
46
47 <p>
48 <label for="user_base">User base (optional; example: cn=People,dc=example,dc=org)</label><br />
49 <input type="text" name="ldap::user_base" id="user_base" value="@@ldap::user_base@@" />
50 </p>
51
52 <p>
53 <label for="uid_attr">uid attribute (default 'uid'; other possible values: sAMAccountName)</label><br />
54 <input type="text" name="ldap::uid_attr" id="uid_attr" value="@@ldap::uid_attr@@" />
55 </p>
56
57 <p>
58 <label for="filter">Filter (example: memberOf=cn=Group,ou=Users,dc=example,dc=org)</label><br />
59 <textarea name="ldap::filter" id="filter" rows="4" cols="50">@@ldap::filter@@</textarea>
60 </p>
61
62 <p>
63 <label for="group_base">Group base (example: ou=Group,dc=example,dc=org)</label><br />
64 <input type="text" name="ldap::group_base" id="group_base" value="@@ldap::group_base@@" />
65 </p>
66
67 <p>
68 <label for="group_attr">Group attribute name (example: memberOf)</label><br />
69 <input type="text" name="ldap::group_attr" id="group_attr" value="@@ldap::group_attr@@" />
70 </p>
71
72 <p>
73 <label for="group_filter">Group filter (optional; example: TODO)</label><br />
74 <input type="text" name="ldap::group_filter" id="group_filter" value="@@ldap::group_filter@@" />
75 </p>
76
77 <p>
78 <label for="admin_group">Admin group (optional; regex; example: cn=(Admins|Admins2),ou=Group,dc=example,dc=org)</label><br />
79 <input type="text" name="ldap::admin_group" id="admin_group" value="@@ldap::admin_group@@" />
80 </p>
81
82 <p>
83 <label for="ca_cert">CA certificates chain to authenticate the LDAP server (optional)</label><br />
84 <textarea name="ldap::ca_cert" id="ca_cert" rows="4" cols="50">@@ldap::ca_cert@@</textarea>
85 </p>
86
87 <input type="submit" name="button" value="@@if(@@ldap::id@@ == 0){{Add}}{{Edit}}" />
88
89 </form>
90 </div>
File root/themes/default/admin/ldap/add_ok.html copied from file root/themes/default/admin/plans/add_ok.html (similarity 100%)
File root/themes/default/admin/ldap/delete_err.html added (mode: 100644) (index 0000000..76c1d52)
1 could not delete the selected LDAP servers (@@errmsg@@)
File root/themes/default/admin/ldap/delete_ok.html added (mode: 100644) (index 0000000..86b133c)
1 <div class="mess ok">
2 The selected LDAP servers have been successfully deleted.
3 </div>
File root/themes/default/admin/ldap/edit_ok.html copied from file root/themes/default/admin/settings/ok.html (similarity 100%)
File root/themes/default/admin/ldap/hints.html added (mode: 100644) (index 0000000..7f9de23)
1 <br />
2 If you want to use <a href="https://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol" target="_blank">LDAP</a>
3 for users and groups, here you can add the servers and their parameters.<br />
4
5 <br />
6 The list will be used in the increasing order of the priority.<br />
File root/themes/default/admin/ldap/list/footer.html added (mode: 100644) (index 0000000..50fc5ce)
1 </table>
2
3 <input type="submit" name="button" value="Delete selected servers" />
4 </form>
File root/themes/default/admin/ldap/list/header.html added (mode: 100644) (index 0000000..81f9416)
1 <form method="post" action="/op/admin/ldap/list" class="form_table">
2 <input type="hidden" name="delete" value="1" />
3 <input type="hidden" name="token" value="@@rg_form_token@@" />
4
5 <table>
6 <tr>
7 <th>Select</th>
8 <th>Name</th>
9 <th>Plan</th>
10 <th>Priority</th>
11 <th>Who</th>
12 <th>Date added (UTC)</th>
13 <th>URL</th>
14 <th>Bind DN</th>
15 <th>User base</th>
16 <th>uid attr</th>
17 <th>Filter</th>
18 <th>Group base</th>
19 <th>Group attr</th>
20 <th>Group filter</th>
21 <th>Admin group</th>
22 <th>CA certificate</th>
23 <th>Operations</th>
24 </tr>
25
File root/themes/default/admin/ldap/list/line.html added (mode: 100644) (index 0000000..1c9fbd9)
1 <tr>
2 <td><input type="checkbox" name="delete_list[@@id@@]" /></td>
3 <td>@@name@@</td>
4 <td>@@plan@@</td>
5 <td>@@prio@@</td>
6 <td>@@who@@</td>
7 <td>@@itime_nice@@</td>
8 <td>@@url@@</td>
9 <td>@@bind_dn@@</td>
10 <td>@@user_base@@</td>
11 <td>@@uid_attr@@</td>
12 <td>@@filter@@</td>
13 <td>@@group_base@@</td>
14 <td>@@group_attr@@</td>
15 <td>@@group_filter@@</td>
16 <td>@@admin_group@@</td>
17 <td>@@ca_cert@@</td>
18 <td><a href="/op/admin/ldap/edit/@@id@@">[Edit]</a></td>
19 </tr>
20
File root/themes/default/admin/ldap/list/nodata.html copied from file root/themes/default/admin/plans/list/nodata.html (similarity 53%) (mode: 100644) (index adc3941..c13be03)
1 1 <div class="mess warning"> <div class="mess warning">
2 No plans defined yet.
2 No LDAP servers defined yet.
3 3 </div> </div>
File root/themes/default/admin/ldap/list_err.html added (mode: 100644) (index 0000000..95ab257)
1 could not list LDAP servers (@@errmsg@@)
File root/themes/default/admin/ldap/menu.html added (mode: 100644) (index 0000000..5d02bab)
1 <div class="menu menu3">
2 <ul>
3 <li@@if(@@menu::ldap::list@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/ldap/list">List</a></li>
4 <li@@if(@@menu::ldap::add@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/ldap/add">Add</a></li>
5 </ul>
6 </div>
File root/themes/default/admin/menu.html changed (mode: 100644) (index 11eeb0f..9e86b0b)
6 6 <li@@if(@@admin_menu::plans@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/plans">Plans</a></li> <li@@if(@@admin_menu::plans@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/plans">Plans</a></li>
7 7 <li@@if(@@admin_menu::users@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/users">Users</a></li> <li@@if(@@admin_menu::users@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/users">Users</a></li>
8 8 <li@@if(@@admin_menu::repos@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/repos">Repos</a></li> <li@@if(@@admin_menu::repos@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/repos">Repos</a></li>
9 <li@@if(@@admin_menu::ldap@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/ldap">LDAP</a></li>
9 10 <li@@if(@@admin_menu::workers@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/workers">Workers</a></li> <li@@if(@@admin_menu::workers@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/workers">Workers</a></li>
10 11 <li@@if(@@admin_menu::invites@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/invites">Invites</a></li> <li@@if(@@admin_menu::invites@@ == 1){{ class="selected"}}{{}}><a href="/op/admin/invites">Invites</a></li>
11 12 </ul> </ul>
File root/themes/default/admin/plans/delete_err.html changed (mode: 100644) (index 7fbd42a..d578f63)
1 could not delete the plans selected (@@errmsg@@)
1 could not delete the selected plans (@@errmsg@@)
File root/themes/default/admin/settings/web/hints.html changed (mode: 100644) (index 10991c1..f76bd9f)
1 1 <br /> <br />
2 - RocketGit will respect the host named defined in the web server to contruct
2 - RocketGit will respect the host name defined in the web server to construct
3 3 URLs; please make sure it is correct. Here you can overwrite it.<br /> URLs; please make sure it is correct. Here you can overwrite it.<br />
4 4 - It is recommended to disable HTTP access and allow only HTTPS.<br /> - It is recommended to disable HTTP access and allow only HTTPS.<br />
5 5 - Do not activate HTTP and/or HTTPS if they are not enabled in the web server. - Do not activate HTTP and/or HTTPS if they are not enabled in the web server.
File samples/nginx.conf changed (mode: 100644) (index 8c7fefc..f73ece0)
1 #upstream rg-php-fpm {
2 # server unix:/run/php-fpm/rocketgit.sock;
3 #}
4
5 1 # HTTP server # HTTP server
6 2 server { server {
7 listen 80 backlog=128 rcvbuf=64k;
8 listen [::]:80 backlog=128 rcvbuf=64k;
3 listen 80;
4 listen [::]:80;
9 5 server_name rg.domain.tld; # add here, space separated, more names server_name rg.domain.tld; # add here, space separated, more names
10 6 server_tokens off; server_tokens off;
11 7 root /usr/share/rocketgit/root; root /usr/share/rocketgit/root;
 
... ... server {
61 57
62 58 # HTTPS server # HTTPS server
63 59 server { server {
64 listen 443 ssl http2 backlog=128 rcvbuf=64k;
65 listen [::]:443 ssl http2 backlog=128 rcvbuf=64k;
60 listen 443 ssl http2;
61 listen [::]:443 ssl http2;
66 62 server_name rg.domain.tld; # add here, space separated, more names server_name rg.domain.tld; # add here, space separated, more names
67 63 server_tokens off; server_tokens off;
68 64 root /usr/share/rocketgit/root; root /usr/share/rocketgit/root;
 
... ... server {
90 86 # Force the use of only one name even if we have more aliases. # Force the use of only one name even if we have more aliases.
91 87 # Before un-commenting it, change SERVERNAME and PORT to real values # Before un-commenting it, change SERVERNAME and PORT to real values
92 88 #if ($host != SERVERNAME) { #if ($host != SERVERNAME) {
93 # rewrite ^/?(.*)$ http://SERVERNAME:PORT/$1 permanent;
89 # rewrite ^/?(.*)$ https://SERVERNAME[:PORT]/$1 permanent;
94 90 #} #}
95 91
96 92 location ~ ^/(favicon\.ico|themes/.*|robots\.txt|\.well-known/.*)$ { location ~ ^/(favicon\.ico|themes/.*|robots\.txt|\.well-known/.*)$ {
File samples/pool.conf changed (mode: 100644) (index c3388c5..7fd6bd9)
... ... request_slowlog_timeout = 2s
412 412 php_admin_value[error_log] = /var/log/php-fpm/rocketgit-error.log php_admin_value[error_log] = /var/log/php-fpm/rocketgit-error.log
413 413 php_admin_flag[log_errors] = on php_admin_flag[log_errors] = on
414 414 php_admin_value[memory_limit] = 128M php_admin_value[memory_limit] = 128M
415 php_admin_value[post_max_size] = 32M
415 php_admin_value[post_max_size] = 512M
File scripts/remote.php changed (mode: 100644) (index f43a90c..b665448)
... ... $https_allow = rg_state_get($db, 'https_allow');
83 83 rg_base_url_build($hostname, $http_allow, $https_allow); rg_base_url_build($hostname, $http_allow, $https_allow);
84 84 rg_log('DEBUG: base_url=' . rg_base_url()); rg_log('DEBUG: base_url=' . rg_base_url());
85 85
86 $login_ui = array('uid' => 0,
87 'username' => 'anonymous user',
88 'organization' => 0);
89
86 90 if (isset($_SERVER['SSH_CONNECTION'])) { if (isset($_SERVER['SSH_CONNECTION'])) {
87 91 rg_log("SSH connection: " . $_SERVER['SSH_CONNECTION']); rg_log("SSH connection: " . $_SERVER['SSH_CONNECTION']);
88 92
 
... ... if (isset($_SERVER['SSH_CONNECTION'])) {
116 120 info('== Welcome to RocketGit! =='); info('== Welcome to RocketGit! ==');
117 121 info('you are connecting from IP ' . $ip . '.'); info('you are connecting from IP ' . $ip . '.');
118 122
119 $login_ui = rg_user_info($db, $login_uid, '', '');
120 if ($login_ui['exists'] != 1)
121 fatal("User does not exists (conn).");
122 info('you are connecting as user \'' . $login_ui['username'] . '\'.');
123 if (strstr($flags, 'N')) {
124 $login_ui = rg_user_info($db, $login_uid, '', '');
125 if ($login_ui['exists'] != 1)
126 fatal("User does not exists (conn).");
127 info('you are connecting as user \''
128 . $login_ui['username'] . '\'.');
123 129
124 putenv('ROCKETGIT_SHOW_INFO=0');
130 putenv('ROCKETGIT_SHOW_INFO=0');
131 }
125 132
126 133 // Only normal keys can execute some commands // Only normal keys can execute some commands
127 134 if (strstr($flags, 'N')) if (strstr($flags, 'N'))
 
... ... if (isset($_SERVER['SSH_CONNECTION'])) {
152 159 $login_uid = 0; $login_uid = 0;
153 160 $key_id = 0; $key_id = 0;
154 161 $flags = ''; $flags = '';
155 $login_ui = array('uid' => 0,
156 'username' => 'anonymous user',
157 'organization' => 0);
158 162
159 163 $line = @fread(STDIN, 8000); $line = @fread(STDIN, 8000);
160 164 $line_len = strlen($line); $line_len = strlen($line);
 
... ... $r = rg_repo_fetch_push_helper($db, $host, $ip, $login_ui, $prefix, $user,
212 216 $repo, $cmd); $repo, $cmd);
213 217 rg_log_ml('DEBUG: repo_fetch_push_helper: ' . print_r($r, TRUE)); rg_log_ml('DEBUG: repo_fetch_push_helper: ' . print_r($r, TRUE));
214 218 if (($r['ok'] !== 1) || ($r['allow'] !== 1)) if (($r['ok'] !== 1) || ($r['allow'] !== 1))
215 fatal($r['error']);
219 fatal($r['errmsg']);
216 220
217 221 $run = "git-shell -c \"" . $cmd . " " . escapeshellarg($r['repo_path']) . "\""; $run = "git-shell -c \"" . $cmd . " " . escapeshellarg($r['repo_path']) . "\"";
218 222 //$run = $cmd . ' ' . escapeshellarg($r['repo_path']); //$run = $cmd . ' ' . escapeshellarg($r['repo_path']);
File scripts/worker.php changed (mode: 100644) (index 504ed4a..c0172c2)
... ... function start_worker($job)
157 157 break; break;
158 158 } }
159 159
160 // We need to allow libvirt access to the image
161 $r = rg_exec('chown qemu:qemu '
162 . escapeshellarg($job['main']), '', FALSE, FALSE);
163 if ($r['ok'] !== 1) {
164 $reason = 'cannot chown build dir to qemu user: ' . $r['errmsg'];
165 break;
166 }
167
160 168 // Save & confirm the receiving (TODO: fsync) // Save & confirm the receiving (TODO: fsync)
161 169 // TODO: This will be used to clean up on a restart // TODO: This will be used to clean up on a restart
162 170 $r = @file_put_contents($job['main'] . '/job.ser', $r = @file_put_contents($job['main'] . '/job.ser',
 
... ... function start_worker($job)
205 213 $do_umount = TRUE; $do_umount = TRUE;
206 214
207 215 // Clone repo // Clone repo
208 putenv('GIT_SSH_COMMAND=ssh'
216 $_env = 'GIT_SSH_COMMAND=ssh'
209 217 . ' -o PasswordAuthentication=no' . ' -o PasswordAuthentication=no'
218 . ' -o ControlMaster=yes'
219 . ' -o IdentitiesOnly=yes'
210 220 . ' -o IdentityFile=' . ' -o IdentityFile='
211 . escapeshellarg($conf['state'] . '/key'));
212 $cmd = 'git clone --depth 1'
221 . escapeshellarg($conf['state'] . '/key');
222 rg_log('DEBUG: env: ' . $_env);
223 putenv($_env);
224 $cmd = ' git clone --depth 1'
213 225 . ' ' . escapeshellarg($job['url']) . ' ' . escapeshellarg($job['url'])
214 226 . ' ' . $emain . '/root/git'; . ' ' . $emain . '/root/git';
215 227 $r = rg_exec($cmd, '', FALSE, FALSE); $r = rg_exec($cmd, '', FALSE, FALSE);
 
... ... function start_worker($job)
257 269 . $lok . $lok
258 270 . 'fi' . "\n\n"; . 'fi' . "\n\n";
259 271 } }
272 rg_log_ml('DEBUG: build.sh: ' . $s);
260 273 $r = @file_put_contents($job['main'] . '/root/build.sh', $s); $r = @file_put_contents($job['main'] . '/root/build.sh', $s);
261 274 if ($r === FALSE) { if ($r === FALSE) {
262 275 $reason = 'cannot store build commands!'; $reason = 'cannot store build commands!';
263 276 break; break;
264 277 } }
265 $r = @chmod($job['main'] . '/root/build.sh', 0700);
278 $r = @chmod($job['main'] . '/root/build.sh', 0755);
266 279 if ($r === FALSE) { if ($r === FALSE) {
267 $reason = 'cannot to chmod on build.sh!';
280 $reason = 'cannot chmod build.sh!';
268 281 break; break;
269 282 } }
270 283
271 284 // Prepare packages - for now, we must list every package // Prepare packages - for now, we must list every package
272 285 // on a single line to avoid not available packages // on a single line to avoid not available packages
273 $pkgs = explode(' ', $job['packages']);
274 if (count($pkgs) > 0) {
286 if (!empty($job['packages'])) {
287 rg_log('DEBUG: packages: ' . $job['packages'] . '.');
288 $pkgs = explode(' ', $job['packages']);
275 289 $p_i_cmd = ''; $p_i_cmd = '';
276 290 $p_i_cmd .= '> /mnt/packages.log' . "\n"; $p_i_cmd .= '> /mnt/packages.log' . "\n";
277 291 foreach ($pkgs as $p) { foreach ($pkgs as $p) {
 
... ... function start_worker($job)
287 301 . 'chown -R build:build /mnt/git /mnt/status' . "\n" . 'chown -R build:build /mnt/git /mnt/status' . "\n"
288 302 . 'date +%s > /mnt/T_START' . "\n" . 'date +%s > /mnt/T_START' . "\n"
289 303 . '# Waiting for net...' . "\n" . '# Waiting for net...' . "\n"
290 . 'while [ -z "`ip ro li | grep ^default`" ]; do' . "\n"
304 . 'while [ "`ip ro li | grep ^default`" = "" ]; do' . "\n"
305 . ' (date; ip ro) &>>/mnt/status/wait_net.log' . "\n"
291 306 . ' sleep 1' . "\n" . ' sleep 1' . "\n"
292 307 . 'done' . "\n" . 'done' . "\n"
308 . 'ip ro li >/mnt/status/iproli.log' . "\n"
293 309 . 'date +%s > /mnt/T_NET_OK' . "\n\n" . 'date +%s > /mnt/T_NET_OK' . "\n\n"
294 310 . $p_i_cmd . $p_i_cmd
295 311 . 'date +%s > /mnt/T_PKGS_OK' . "\n\n" . 'date +%s > /mnt/T_PKGS_OK' . "\n\n"
296 . 'su - build -c /mnt/build.sh' . "\n"
297 . 'date +%s > /mnt/T_DONE' . "\n\n"
312 . 'su - build -c /mnt/build.sh &>/mnt/status/build.log' . "\n\n"
298 313 . 'sync' . "\n" . 'sync' . "\n"
299 . 'shutdown -h now'
314 . 'date +%s > /mnt/T_DONE' . "\n\n"
315 . 'xxxshutdown -h now'
300 316 ); );
301 317 if ($r === FALSE) { if ($r === FALSE) {
302 318 $reason = 'cannot store commands!'; $reason = 'cannot store commands!';
 
... ... function start_worker($job)
315 331 } }
316 332 $do_umount = FALSE; $do_umount = FALSE;
317 333
334 // We need to allow libvirt access to the image
335 $r = rg_exec('chown qemu:qemu ' . $img2, '', FALSE, FALSE);
336 if ($r['ok'] !== 1) {
337 $reason = 'cannot chown image to qemu user: ' . $r['errmsg'];
338 break;
339 }
340
318 341 // . ' --noautoconsole' // . ' --noautoconsole'
319 342 // . ' --security type=dynamic,relabel=yes' // . ' --security type=dynamic,relabel=yes'
320 343 // . ' --filesystem source=' . $emain . '/root') // . ' --filesystem source=' . $emain . '/root')
 
... ... function start_worker($job)
323 346 $r = rg_exec('virt-install' $r = rg_exec('virt-install'
324 347 . ' --name ' . $ename . ' --name ' . $ename
325 348 . ' --arch ' . escapeshellarg($env['arch']) . ' --arch ' . escapeshellarg($env['arch'])
326 . ' --memory 256'
349 . ' --memory 400'
327 350 . ' --vcpus 1' . ' --vcpus 1'
328 351 . ' --graphics none' . ' --graphics none'
329 352 . ' --network network=default' . ' --network network=default'
 
... ... while(1) {
615 638 } }
616 639
617 640 // TODO: do we clean the pool in case of crash? // TODO: do we clean the pool in case of crash?
618 $cmd = 'virsh pool-undefine rocketgit-j-' . $jid;
619 $r = rg_exec($cmd, '', FALSE, FALSE);
620 if ($r['ok'] != 1) {
621 $job['error'] = 'Could not undefine pool: ' . $r['errmsg'];
622 rg_log('Error: ' . $job['error']);
623 //break; TODO: do we need to do this?!
624 }
625
626 // TODO: do we clean the machine in case of crash?
627 $cmd = 'virsh undefine rg-worker-' . escapeshellarg($jid);
628 $r = rg_exec($cmd, '', FALSE, FALSE);
629 if ($r['ok'] != 1) {
630 $job['error'] = 'Could not undefine machine: ' . $r['errmsg'];
631 rg_log('Error: ' . $job['error']);
632 //break; TODO
633 }
641 // $cmd = 'virsh pool-undefine rocketgit-j-' . $jid;
642 // $r = rg_exec($cmd, '', FALSE, FALSE);
643 // if ($r['ok'] != 1) {
644 // $job['error'] = 'Could not undefine pool: ' . $r['errmsg'];
645 // rg_log('Error: ' . $job['error']);
646 // //break; TODO: do we need to do this?!
647 // }
648
649 // // TODO: do we clean the machine in case of crash?
650 // $cmd = 'virsh undefine rg-worker-' . escapeshellarg($jid);
651 // $r = rg_exec($cmd, '', FALSE, FALSE);
652 // if ($r['ok'] != 1) {
653 // $job['error'] = 'Could not undefine machine: ' . $r['errmsg'];
654 // rg_log('Error: ' . $job['error']);
655 // //break; TODO
656 // }
657
658 // $cmd = 'virsh destroy rocketgit-j-' . $jid;
659 // $r = rg_exec($cmd, '', FALSE, FALSE);
660 // if ($r['ok'] != 1) {
661 // $job['error'] = 'Could not destroy: ' . $r['errmsg'];
662 // rg_log('Error: ' . $job['error']);
663 // }
634 664 } }
635 665 } }
636 666
File tests/Makefile changed (mode: 100644) (index bfb603e..06d4435)
... ... clean:
15 15 http.arond *.pub git2key git2 *.in q_merge_requests/mr-* \ http.arond *.pub git2key git2 *.in q_merge_requests/mr-* \
16 16 qstats/* repos/* helper helper.pub keys/* ca *.pid \ qstats/* repos/* helper helper.pub keys/* ca *.pid \
17 17 *.tmp base ubase wh_cloud.git export.json \ *.tmp base ubase wh_cloud.git export.json \
18 .by_http temp_repos jars
18 .by_http temp_repos jars \
19 ldap/chroot ldap/chroot-*
19 20
20 21 .PHONY: clean-state .PHONY: clean-state
21 22 clean-state: clean-state:
File tests/_run_tests.sh changed (mode: 100755) (index 8be3399..a121157)
1 1 #!/bin/bash #!/bin/bash
2 2
3 tests="admin_set_web git_big_push admin_set_git by_http wh_lambda http_keys \
3 tests="ldap ldap_core ldap \
4 admin_set_web git_big_push admin_set_git by_http wh_lambda http_keys \
4 5 http_forgot \ http_forgot \
5 6 api wh_cloud pr_anon wh_http ssh http_totp totp git_log1 \ api wh_cloud pr_anon wh_http ssh http_totp totp git_log1 \
6 7 http_admin http_bug \ http_admin http_bug \
File tests/admin_set_git.php changed (mode: 100644) (index 0c456e1..0b1384c)
... ... prepare_http();
25 25
26 26 $rg_ui = array('is_admin' => 1); $rg_ui = array('is_admin' => 1);
27 27 rg_test_create_user($db, $rg_ui); rg_test_create_user($db, $rg_ui);
28 test_login($test_url, $rg_ui);
28 $r = test_login($test_url, $rg_ui);
29 if ($r === FALSE) {
30 rg_log("Cannot login!");
31 exit(1);
32 }
29 33
30 34
31 35 rg_log(''); rg_log('');
 
... ... foreach ($list as $var => $def) {
66 70 $r = do_req($test_url . '/op/admin/settings/git', $data, $headers); $r = do_req($test_url . '/op/admin/settings/git', $data, $headers);
67 71 if (!strstr($r['body'], 'Configuration has been successfully saved.')) { if (!strstr($r['body'], 'Configuration has been successfully saved.')) {
68 72 rg_log_ml('r: ' . print_r($r, TRUE)); rg_log_ml('r: ' . print_r($r, TRUE));
69 rg_log("Cannot post form!");
73 rg_log("Cannot post form (expected answer missing)!");
70 74 exit(1); exit(1);
71 75 } }
72 76 rg_log_exit(); rg_log_exit();
File tests/admin_set_web.php changed (mode: 100644) (index de51f32..8c73afd)
... ... prepare_http();
25 25
26 26 $rg_ui = array('is_admin' => 1); $rg_ui = array('is_admin' => 1);
27 27 rg_test_create_user($db, $rg_ui); rg_test_create_user($db, $rg_ui);
28 test_login($test_url, $rg_ui);
28 $r = test_login($test_url, $rg_ui);
29 if ($r === FALSE) {
30 rg_log("Cannot login!");
31 exit(1);
32 }
29 33
30 34
31 35 rg_log(''); rg_log('');
 
... ... foreach ($list as $var => $def) {
68 72 $r = do_req($test_url . '/op/admin/settings/web', $data, $headers); $r = do_req($test_url . '/op/admin/settings/web', $data, $headers);
69 73 if (!strstr($r['body'], 'Configuration has been successfully saved.')) { if (!strstr($r['body'], 'Configuration has been successfully saved.')) {
70 74 rg_log_ml('r: ' . print_r($r, TRUE)); rg_log_ml('r: ' . print_r($r, TRUE));
71 rg_log("Cannot post form!");
75 rg_log("Cannot post form (expected answer missing)!");
72 76 exit(1); exit(1);
73 77 } }
74 78 rg_log_exit(); rg_log_exit();
File tests/config.php changed (mode: 100644) (index 750185e..6bfc906)
3 3 // Defaults // Defaults
4 4 $rg_base = dirname(__FILE__); $rg_base = dirname(__FILE__);
5 5 $rg_sql = "dbname=trg connect_timeout=10"; $rg_sql = "dbname=trg connect_timeout=10";
6 $rg_sql_debug = 1;
6 if (!isset($rg_sql_debug))
7 $rg_sql_debug = 1;
7 8 $rg_session_time = 3600; $rg_session_time = 3600;
8 9 $rg_keys_file = "afile.txt"; $rg_keys_file = "afile.txt";
9 10 $rg_scripts = dirname(dirname(__FILE__)); $rg_scripts = dirname(dirname(__FILE__));
File tests/helpers.inc.php changed (mode: 100644) (index 8d3502c..7d7e0ac)
... ... function rg_test_create_user($db, &$rg_ui)
35 35 $new['pass2'] = 'pass-' . $_user_id . ':'; $new['pass2'] = 'pass-' . $_user_id . ':';
36 36 $new['disk_used_mb'] = 0; $new['disk_used_mb'] = 0;
37 37 $new['last_ip'] = '?'; $new['last_ip'] = '?';
38 $new['ask_for_email_confirmation'] = 0;
39 38 $_user_id++; $_user_id++;
40 39
41 40 // Delete old user // Delete old user
File tests/http.inc.php changed (mode: 100644) (index 5b4392f..63d5cd8)
... ... function do_req($url, &$data, &$headers)
92 92 curl_setopt($c, CURLOPT_COOKIEJAR, $cookie_jar); curl_setopt($c, CURLOPT_COOKIEJAR, $cookie_jar);
93 93 curl_setopt($c, CURLOPT_COOKIEFILE, $cookie_jar); curl_setopt($c, CURLOPT_COOKIEFILE, $cookie_jar);
94 94
95 // HTTP/2
96 if (curl_version()['features'] & CURL_VERSION_HTTP2)
97 curl_setopt($c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
98
95 99 $err = @fopen('php://temp', 'w'); $err = @fopen('php://temp', 'w');
96 100 if ($err !== FALSE) { if ($err !== FALSE) {
97 101 curl_setopt($c, CURLOPT_STDERR, $err); curl_setopt($c, CURLOPT_STDERR, $err);
 
... ... function test_login($url, $rg_ui)
243 247 "pass" => $rg_ui['pass'], "pass" => $rg_ui['pass'],
244 248 "lock_ip" => 1 "lock_ip" => 1
245 249 ); );
250 if (isset($rg_ui['t']))
251 $data['t'] = $rg_ui['t'];
246 252 $headers = array(); $headers = array();
247 253 $r = do_req($url . "/op/login", $data, $headers); $r = do_req($url . "/op/login", $data, $headers);
248 254 if ($r === FALSE) { if ($r === FALSE) {
File tests/http_keys.php changed (mode: 100644) (index e0a9a9a..c443a52)
... ... prepare_http();
25 25
26 26 $rg_ui = array('is_admin' => 1); $rg_ui = array('is_admin' => 1);
27 27 rg_test_create_user($db, $rg_ui); rg_test_create_user($db, $rg_ui);
28 test_login($test_url, $rg_ui);
28 $r = test_login($test_url, $rg_ui);
29 if ($r === FALSE) {
30 rg_log("Cannot login!");
31 exit(1);
32 }
29 33
30 34
31 35 rg_log(''); rg_log('');
 
... ... foreach ($list as $var => $def) {
70 74 $r = do_req($test_url . '/op/admin/settings/ssh', $data, $headers); $r = do_req($test_url . '/op/admin/settings/ssh', $data, $headers);
71 75 if (!strstr($r['body'], 'Configuration has been successfully saved.')) { if (!strstr($r['body'], 'Configuration has been successfully saved.')) {
72 76 rg_log_ml('r: ' . print_r($r, TRUE)); rg_log_ml('r: ' . print_r($r, TRUE));
73 rg_log("Cannot post form!");
77 rg_log("Cannot post form (expected answer missing)!");
74 78 exit(1); exit(1);
75 79 } }
76 80 rg_log_exit(); rg_log_exit();
File tests/ldap.php added (mode: 100644) (index 0000000..c306001)
1 <?php
2 error_reporting(E_ALL | E_STRICT);
3 ini_set('track_errors', 'On');
4
5 $rg_cache_debug = TRUE;
6 $rg_util_debug = TRUE;
7 $rg_sql_debug = 100;
8
9 $INC = dirname(__FILE__) . '/../inc';
10 require_once(dirname(__FILE__) . '/config.php');
11 require_once($INC . '/init.inc.php');
12 require_once($INC . '/util.inc.php');
13 require_once($INC . '/ldap.inc.php');
14 require_once($INC . '/ldap_sync.inc.php');
15 require_once('helpers.inc.php');
16 require_once('http.inc.php');
17
18 rg_log_set_file('ldap.log');
19
20 $rg_sql = 'host=localhost user=rocketgit dbname=rocketgit connect_timeout=10';
21 $rg_no_db = TRUE;
22 require_once('common.php');
23
24 $_testns = 'admin_ldap';
25 $rg_cache_enable = TRUE;
26 $rg_cache_debug = TRUE;
27
28
29 function rg_ldap_start_server(&$l)
30 {
31 $prep = 'ldap/chroot-' . $l['rg_ldap_ns'] . '/prep.done';
32 $r = @unlink($prep);
33 rg_log('unlinking prep.done returned ' . ($r === FALSE ? 'false' : 'true'));
34
35 $log = __DIR__ . '/ldap-' . $l['rg_ldap_port'] . '.log';
36
37 $pid = pcntl_fork();
38 if ($pid == 0) { // child
39 foreach ($l as $k => $v) {
40 rg_log($k . '=' . $v);
41 putenv($k . '=' . $v);
42 }
43 rg_exec('cd ldap && sh start.sh &> ' . $log, '', FALSE, FALSE);
44
45 $log = '../ldap-' . $l['rg_ldap_port'] . 'prep.log';
46 rg_exec('cd ldap && sh prepare.sh &> ' . $log, '', FALSE, FALSE);
47 exit(0);
48 }
49
50 rg_log('Child started with pid ' . $pid);
51
52 rg_log('Waiting for preparation to finish...');
53 $tries = 200;
54 while ($tries-- > 0) {
55 $x = @file_get_contents($prep);
56 if ($x !== FALSE)
57 break;
58
59 rg_log('prep file [' . $prep . '] is not present, wait.');
60 usleep(100000);
61 }
62
63 if ($tries == 0) {
64 rg_log('Could not prepare! Exit!');
65 posix_kill($pid, SIGKILL);
66 exit(1);
67 }
68
69 $l['log'] = $log;
70 }
71
72 function clean($log)
73 {
74 rg_log('Cleaning processes attached to file ' . $log . '...');
75 $r = rg_exec('fuser -k -v -9 ' . escapeshellarg($log), '', FALSE, FALSE);
76 rg_log_ml('fuser returned: ' . print_r($r, TRUE));
77 }
78
79
80 prepare_http();
81
82 $rg_ui = array('is_admin' => 1);
83 rg_test_create_user($db, $rg_ui);
84 $r = test_login($test_url, $rg_ui);
85 if ($r === FALSE) {
86 rg_log("Cannot login!");
87 exit(1);
88 }
89
90
91 rg_log('');
92 rg_log('Generating certificates...');
93 $r = rg_exec('./ca.sh ldap', '', FALSE, FALSE);
94 if (!strstr($r['data'], 'CA_SH_OK')) {
95 rg_log_ml('data: ' . $r['data']);
96 rg_log('Cannot generate certificates!');
97 exit(1);
98 }
99
100
101 $bind_addr = '127.' . rand(1, 255) . '.' . rand(1,255) . '.' . rand(2,255);
102 $bind_port = 65100; $bind_ports = 65101;
103 $pass = rg_id(16);
104 $user_pass = rg_id(16);
105 $user_key = rg_id(16);
106 rg_log('bind_addr=' . $bind_addr . ' bind_port=' . $bind_port
107 . ' bind_ports=' . $bind_ports . ' pass=' . $pass
108 . ' user_pass=' . $user_pass . ' user_key=' . $user_key);
109
110
111 rg_log('');
112 rg_log_enter('Deleting all LDAP servers');
113 $sql = 'TRUNCATE ldap_servers';
114 $res = rg_sql_query($db, $sql);
115 if ($res === FALSE) {
116 rg_log('Cannot delete all LDAP servers');
117 exit(1);
118 }
119 rg_sql_free_result($res);
120 rg_cache_unset('ldap', RG_SOCKET_NO_WAIT);
121 rg_log_exit();
122
123
124 rg_log('');
125 rg_log_enter('Deleting LDAP cache');
126 $sql = 'TRUNCATE ldap_cache';
127 $res = rg_sql_query($db, $sql);
128 if ($res === FALSE) {
129 rg_log('Cannot delete LDAP cache');
130 exit(1);
131 }
132 rg_sql_free_result($res);
133 //TODO rg_cache_unset('ldap_cache', RG_SOCKET_NO_WAIT);
134 rg_log_exit();
135
136
137 rg_log('');
138 rg_log_enter('Loading Admin -> LDAP -> Add...');
139 $data = array();
140 $headers = array();
141 $r = do_req($test_url . '/op/admin/ldap/add', $data, $headers);
142 if ($r === FALSE) {
143 rg_log('Cannot load add page!');
144 exit(1);
145 }
146 if (!isset($r['tokens']['ldap_add'])) {
147 rg_log_ml('r:' . print_r($r, TRUE));
148 rg_log('No ldap_add token?!');
149 exit(1);
150 }
151 $token = $r['tokens']['ldap_add'];
152 $id = rg_id(8);
153 $name = 'server-' . $id . ' <xss>';
154
155 rg_log('Posting the form...');
156 $data = array(
157 'doit' => 1,
158 'token' => $token,
159 'ldap::id' => 0,
160 'ldap::plan_id' => 0,
161 'ldap::prio' => 10,
162 'ldap::session_time' => 600,
163 'ldap::name' => $name,
164 'ldap::url' => 'ldap://' . $bind_addr . ':' . $bind_port,
165 'ldap::bind_dn' => '',
166 'ldap::bind_pass' => '',
167 'ldap::user_base' => 'dc=my-domain,dc=com',
168 'ldap::uid_attr' => 'uid',
169 'ldap::filter' => 'memberOf=cn=group1,ou=Group,dc=my-domain,dc=com',
170 'ldap::group_base' => 'dc=my-domain,dc=com',
171 'ldap::group_attr' => 'memberOf',
172 'ldap::group_filter' => '',
173 'ldap::admin_group' => 'cn=(Admins|Admins2),ou=Group,dc=my-domain,dc=com',
174 'ldap::ca_cert' => ''
175 );
176 $r = do_req($test_url . '/op/admin/ldap/add', $data, $headers);
177 if (!strstr($r['body'], 'Configuration has been successfully saved.')) {
178 rg_log_ml('r: ' . print_r($r, TRUE));
179 rg_log('Cannot post form (expected answer missing)!');
180 exit(1);
181 }
182 rg_log_exit();
183
184
185 rg_log('');
186 rg_log_enter('Loading Admin -> LDAP -> List...');
187 $data = array();
188 $headers = array();
189 $r = do_req($test_url . '/op/admin/ldap/list', $data, $headers);
190 if ($r === FALSE) {
191 rg_log('Cannot load list page!');
192 exit(1);
193 }
194 // TODO, here test that everything is present in the list
195 $token = $r['tokens']['ldap_list'];
196 rg_log_exit();
197
198
199 rg_log('');
200 rg_log_enter('Setting up two LDAP servers in mirror mode...');
201 // We are forced to close the connection, else will get a nasty error,
202 // Even if the child is not doing anything with the connection.
203 rg_sql_close($db);
204 $l1 = array(
205 'rg_ldap_ns' => 's1',
206 'rg_ldap_addr' => $bind_addr,
207 'rg_ldap_port' => $bind_port,
208 'rg_ldap_ports' => $bind_ports,
209 'rg_ldap_server_id' => '001',
210 'rg_ldap_producer_url' => 'ldap://' . $bind_addr . ':' . ($bind_port + 2),
211 'rg_ldap_producer_rid' => '002',
212 'rg_ldap_add_data' => 1,
213 'rg_ldap_pass' => $pass,
214 'rg_ldap_user_pass' => $user_pass,
215 'rg_ldap_user_key' => $user_key
216 );
217 rg_ldap_start_server($l1);
218
219 $l2 = array(
220 'rg_ldap_ns' => 's2',
221 'rg_ldap_addr' => $bind_addr,
222 'rg_ldap_port' => $bind_port + 2,
223 'rg_ldap_ports' => $bind_ports + 2,
224 'rg_ldap_server_id' => '002',
225 'rg_ldap_producer_url' => 'ldap://' . $bind_addr . ':' . $bind_port,
226 'rg_ldap_producer_rid' => '001',
227 'rg_ldap_add_data' => 0,
228 'rg_ldap_pass' => $pass,
229 'rg_ldap_user_pass' => $user_pass,
230 'rg_ldap_user_key' => $user_key
231 );
232 rg_ldap_start_server($l2);
233
234 register_shutdown_function('clean', $l1['log']);
235 register_shutdown_function('clean', $l2['log']);
236
237 $data = array(
238 'addr' => $bind_addr,
239 'port' => $bind_port,
240 'bind_user' => 'cn=Manager,dc=my-domain,dc=com',
241 'bind_pass' => $pass,
242 'base' => 'dc=my-domain,dc=com'
243 );
244 rg_log_exit();
245
246
247 rg_log('');
248 rg_log_enter('Find out the id of the server...');
249 $r = rg_ldap_list($db);
250 if ($r['ok'] !== 1) {
251 rg_log('Cannot get the ldap servers list: ' . $r['errmsg']);
252 exit(1);
253 }
254 $found = FALSE;
255 foreach ($r['list'] as $id => $info) {
256 if (strcmp($info['url'], 'ldap://' . $bind_addr . ':' . $bind_port) != 0)
257 continue;
258
259 $found = TRUE;
260 break;
261 }
262 if (!$found) {
263 rg_log('Could not find the server in database!');
264 exit(1);
265 }
266 $data['server_id'] = $id;
267 rg_log_exit();
268
269
270 /* TODO: this has to be made available after I deal with the sync
271 rg_log('');
272 rg_log_enter('sync_ro...');
273 $r = rg_ldap_sync_ro($db, $data);
274 if ($r['ok'] != 1) {
275 rg_log('Cannot sync: ' . $r['errmsg'] . '!');
276 exit(1);
277 }
278 rg_log_exit();
279
280
281 rg_log('');
282 rg_log_enter('Deleting user user4...');
283 $r = rg_ldap_core_connect('ldap://' . $l1['rg_ldap_addr']
284 . ':' . $l1['rg_ldap_port']);
285 if ($r['ok'] !== 1) {
286 rg_log('Cannot connect to second server: ' . $r['errmsg'] . '!');
287 exit(1);
288 }
289 $con = $r['con'];
290 $r = rg_ldap_core_bind($con, 'cn=Manager,dc=my-domain,dc=com', $pass);
291 if ($r['ok'] !== 1) {
292 rg_log('cannot bind: ' . $r['errmsg']);
293 exit(1);
294 }
295 $r = rg_ldap_core_del($con, 'uid=user4,ou=People,dc=my-domain,dc=com');
296 if ($r['ok'] !== 1) {
297 rg_log('Cannot delete: ' . $r['errmsg'] . '!');
298 exit(1);
299 }
300 rg_log_exit();
301
302 // TODO: needed?!
303 sleep(3);
304
305
306 rg_log('');
307 rg_log_enter('get server CSN field...');
308 $res = rg_sql_query($db, 'SELECT csn FROM ldap_servers'
309 . ' WHERE id = ' . $data['server_id']);
310 if ($res === FALSE) {
311 rg_log('Cannot select csn from db: ' . rg_sql_error() . '!');
312 exit(1);
313 }
314 $row = rg_sql_fetch_array($res);
315 rg_sql_free_result($res);
316 $csn = $row['csn'];
317 rg_log('csn: ' . $csn);
318 rg_log_exit();
319
320
321 rg_log('');
322 rg_log_enter('sync_ro (after a delete)...');
323 $data['rid'] = '001'; $data['csn'] = $csn; // not sure if rid is correct TODO
324 $r = rg_ldap_sync_ro($db, $data);
325 if ($r['ok'] != 1) {
326 rg_log('Cannot sync: ' . $r['errmsg'] . '!');
327 exit(1);
328 }
329 rg_log_exit();
330 */
331
332
333 rg_log('');
334 rg_log_enter('Login using a LDAP user using ldap uid (first login)');
335 $_ui = array(
336 'username' => 'user1-' . $user_key,
337 'pass' => $user_pass,
338 't' => 'first login by uid'
339 );
340 $r = test_login($test_url, $_ui);
341 if ($r === FALSE)
342 exit(1);
343 rg_log_exit();
344
345
346 rg_log('');
347 rg_log_enter('Setting ldap_cache.uid to 0 to trigger a conflict in inserting'
348 . ' in \'users\' table');
349 $params = array('user' => 'user1-' . $user_key);
350 $sql = 'UPDATE ldap_cache SET uid = 0 WHERE ldap_uid = @@user@@';
351 $res = rg_sql_query_params($db, $sql, $params);
352 if ($res === FALSE) {
353 rg_log('Cannot update ldap_cache.uid!');
354 exit(1);
355 }
356 rg_sql_free_result($res);
357 rg_log_exit();
358
359
360 rg_log('');
361 // User will not be found in 'users' table because we search by e-mail
362 rg_log_enter('Login using a LDAP user: mail');
363 $_ui = array(
364 'username' => 'user1-' . $user_key . '@my-domain.com',
365 'pass' => $user_pass,
366 't' => 'login by e-mail expecting conflict inserting into users table'
367 );
368 $r = test_login($test_url, $_ui);
369 if ($r === FALSE)
370 exit(1);
371 rg_log_exit();
372
373
374 rg_log('');
375 rg_log_enter('Login using a LDAP user: uid (second time, expect user present)');
376 $_ui = array(
377 'username' => 'user1-' . $user_key,
378 'pass' => $user_pass,
379 't' => 'second login by uid, expecting user present in users table'
380 );
381 $r = test_login($test_url, $_ui);
382 if ($r === FALSE) {
383 rg_log('Cannot login!');
384 exit(1);
385 }
386 rg_log_exit();
387
388
389 rg_log('');
390 rg_log_enter('Login using a LDAP user: uid (third time, but delete from'
391 . ' \'users\' table first)');
392 $params = array(
393 'new' => 'user1-fake-' . $user_key,
394 'old' => 'user1-' . $user_key
395 );
396 // First, find out the uid
397 $sql = 'SELECT uid FROM users WHERE username = @@old@@';
398 $res = rg_sql_query_params($db, $sql, $params);
399 if ($res === FALSE) {
400 rg_log('Cannot get info user1 username!');
401 exit(1);
402 }
403 $row = rg_sql_fetch_array($res);
404 rg_sql_free_result($res);
405 $params['uid'] = $row['uid'];
406
407 $sql = 'UPDATE users SET username = @@new@@ WHERE uid = @@uid@@';
408 $res = rg_sql_query_params($db, $sql, $params);
409 if ($res === FALSE) {
410 rg_log('Cannot update user1 username!');
411 exit(1);
412 }
413
414 $k = 'username_to_uid::user1-' . $user_key;
415 rg_cache_unset($k, RG_SOCKET_NO_WAIT);
416
417 $k = 'user::' . $params['uid'];
418 rg_cache_unset($k, RG_SOCKET_NO_WAIT);
419
420 $_ui = array(
421 'username' => 'user1-' . $user_key,
422 'pass' => $user_pass,
423 't' => 'login by uid, but delete from users before'
424 );
425 $r = test_login($test_url, $_ui);
426 if ($r === FALSE) {
427 rg_log('Cannot login!');
428 exit(1);
429 }
430 rg_log_exit();
431
432
433 rg_log('');
434 rg_log_enter('We try to login with user2, which have the description as the uid');
435 rg_log('Updating LDAP server...');
436 rg_cache_set('ldap::list::' . $data['server_id'] . '::uid_attr',
437 'DescriptioN', RG_SOCKET_NO_WAIT);
438 $_ui = array(
439 'username' => 'user2-' . $user_key,
440 'pass' => $user_pass,
441 't' => 'now, the uid attr field is description'
442 );
443 $r = test_login($test_url, $_ui);
444 if ($r === FALSE) {
445 rg_log('Cannot login!');
446 exit(1);
447 }
448 rg_log_exit();
449
450
451 rg_log('');
452 rg_log_enter('Login again as the admin user...');
453 $r = test_login($test_url, $rg_ui);
454 if ($r === FALSE) {
455 rg_log("Cannot login!");
456 exit(1);
457 }
458 rg_log_exit();
459
460
461 rg_log('');
462 rg_log_enter('Loading Admin -> LDAP -> List (for delete)...');
463 $data = array();
464 $headers = array();
465 $r = do_req($test_url . '/op/admin/ldap/list', $data, $headers);
466 if ($r === FALSE) {
467 rg_log('Cannot load list page!');
468 exit(1);
469 }
470 $token = $r['tokens']['ldap_list'];
471 rg_log_exit();
472
473
474 rg_log('');
475 rg_log_enter('Deleting a LDAP server...');
476 $sql = 'SELECT id FROM ldap_servers WHERE name = @@name@@ AND who = @@who@@';
477 $params = array('who' => $rg_ui['uid'], 'name' => $name);
478 $res = rg_sql_query_params($db, $sql, $params);
479 if ($res === FALSE) {
480 rg_log('Cannot do the select query: ' . rg_sql_error() . '!');
481 exit(1);
482 }
483 $row = rg_sql_fetch_array($res);
484 rg_sql_free_result($res);
485 $_id = $row['id'];
486 $data = array(
487 'delete' => 1,
488 'token' => $token,
489 'delete_list[' . $_id . ']' => 'on'
490 );
491 $headers = array();
492 $r = do_req($test_url . '/op/admin/ldap/list', $data, $headers);
493 if ($r === FALSE) {
494 rg_log('Cannot load list page!');
495 exit(1);
496 }
497 if (!strstr($r['body'], 'The selected LDAP servers have been successfully deleted.')) {
498 rg_log_ml('r: ' . print_r($r, TRUE));
499 rg_log('Cannot delete LDAP server!');
500 exit(1);
501 }
502 rg_log_exit();
503
504
505 rg_log('OK!');
506 ?>
File tests/ldap/.gitignore added (mode: 100644) (index 0000000..0196b12)
1 *.sock
2 chroot
3 chroot-s1
4 chroot-s2
File tests/ldap/1.php added (mode: 100644) (index 0000000..3526dcc)
1 <?php
2 error_reporting(E_ALL);
3
4
5 $INC = __DIR__ . '/../../inc';
6 require_once $INC . '/ldap.inc.php';
7
8 $r = rg_ldap_connect('ldap://127.0.0.1:65001');
9 if ($r['ok'] !== 1) {
10 echo 'Cannot connect: ' . $r['errmsg'] . "\n";
11 exit(1);
12 }
13
14 $con = $r['con'];
15 $r = rg_ldap_bind($con, 'cn=Manager,dc=my-domain,dc=com', 'aaaaaa');
16 if ($r['ok'] !== 1) {
17 echo 'Cannot bind: ' . $r['errmsg'] . "\n";
18 exit(1);
19 }
20
21 $org = time();
22
23 $a = array(
24 'objectClass' => 'organization',
25 'o' => 'Org-' . $org
26 );
27 $r = rg_ldap_add($con, 'o=Org-' . $org . ',dc=my-domain,dc=com', $a);
28 if ($r['ok'] !== 1) {
29 echo 'Cannot add: ' . $r['errmsg'] . "\n";
30 exit(1);
31 }
32
33 $a = array(
34 'objectClass' => 'groupOfNames',
35 'cn' => 'group3',
36 'member' => 'uid=invalid,ou=People,dc=my-domain,dc=com'
37 );
38 $r = rg_ldap_add($con, 'cn=groupx,ou=Group,dc=my-domain,dc=com', $a);
39 if ($r['ok'] !== 1) {
40 echo 'Cannot add: ' . $r['errmsg'] . "\n";
41 exit(1);
42 }
43
44 echo "OK!\n";
45
46 ?>
47
File tests/ldap/README added (mode: 100644) (index 0000000..01d55a0)
1 Seems a restart is required to obtain ContextCSN in the first block.
2 Yes, because it is stored on disk only after restart.
3 But, it can be queried (see get_ContextCSN.sh script) - it is working
4 without restart.
5
6 But, I can use entryCSN as sync=rp csn= parameter!
7 Pay attention! We may have several servers: csn= ContextCSNs must be ';' separated
8
9 man slapd: search for cookie
10 sid= is the ServerID
11
12 Use -o ldif-wrap=no for ldapsearch, to not wrap lines.
13
File tests/ldap/add_user.sh added (mode: 100755) (index 0000000..067e917)
1 #!/bin/bash
2
3 set -e
4
5 u="user-`date +%s`"
6
7 cat <<EOF | ldapadd -x -waaaaaa -D "cn=Manager,dc=my-domain,dc=com" -H ldapi://ldapi.sock
8 dn: uid=${u},ou=People,dc=my-domain,dc=com
9 objectClass: top
10 objectClass: inetOrgPerson
11 uid: ${u}
12 userPassword: bbbbbb
13 sn: surname
14 cn: ${u}
15 EOF
File tests/ldap/conf.tmpl/cn=config.ldif added (mode: 100644) (index 0000000..b94de2c)
1 # AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
2 # CRC32 3db1ba94
3 dn: cn=config
4 objectClass: olcGlobal
5 cn: config
6 olcTLSCACertificatePath: /etc/openldap/certs
7 olcTLSCertificateFile: "OpenLDAP Server"
8 olcTLSCertificateKeyFile: /etc/openldap/certs/password
9 structuralObjectClass: olcGlobal
10 entryUUID: 38c4c7ce-fc43-1036-9074-ebf5d4043f34
11 creatorsName: cn=config
12 createTimestamp: 20170713181706Z
13 entryCSN: 20170713181706.279712Z#000000#000#000000
14 modifiersName: cn=config
15 modifyTimestamp: 20170713181706Z
File tests/ldap/conf.tmpl/cn=config/cn=schema.ldif added (mode: 100644) (index 0000000..0653e00)
1 # AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
2 # CRC32 11f89c6c
3 dn: cn=schema
4 objectClass: olcSchemaConfig
5 cn: schema
6 structuralObjectClass: olcSchemaConfig
7 entryUUID: 38c5106c-fc43-1036-9075-ebf5d4043f34
8 creatorsName: cn=config
9 createTimestamp: 20170713181706Z
10 entryCSN: 20170713181706.282255Z#000000#000#000000
11 modifiersName: cn=config
12 modifyTimestamp: 20170713181706Z
File tests/ldap/conf.tmpl/cn=config/cn=schema/cn={0}core.ldif added (mode: 100644) (index 0000000..9752c08)
1 # AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
2 # CRC32 8757baa8
3 dn: cn={0}core
4 objectClass: olcSchemaConfig
5 cn: {0}core
6 olcAttributeTypes: {0}( 2.5.4.2 NAME 'knowledgeInformation' DESC 'RFC2256: k
7 nowledge information' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.
8 121.1.15{32768} )
9 olcAttributeTypes: {1}( 2.5.4.4 NAME ( 'sn' 'surname' ) DESC 'RFC2256: last
10 (family) name(s) for which the entity is known by' SUP name )
11 olcAttributeTypes: {2}( 2.5.4.5 NAME 'serialNumber' DESC 'RFC2256: serial nu
12 mber of the entity' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMat
13 ch SYNTAX 1.3.6.1.4.1.1466.115.121.1.44{64} )
14 olcAttributeTypes: {3}( 2.5.4.6 NAME ( 'c' 'countryName' ) DESC 'RFC4519: tw
15 o-letter ISO-3166 country code' SUP name SYNTAX 1.3.6.1.4.1.1466.115.121.1.
16 11 SINGLE-VALUE )
17 olcAttributeTypes: {4}( 2.5.4.7 NAME ( 'l' 'localityName' ) DESC 'RFC2256: l
18 ocality which this object resides in' SUP name )
19 olcAttributeTypes: {5}( 2.5.4.8 NAME ( 'st' 'stateOrProvinceName' ) DESC 'RF
20 C2256: state or province which this object resides in' SUP name )
21 olcAttributeTypes: {6}( 2.5.4.9 NAME ( 'street' 'streetAddress' ) DESC 'RFC2
22 256: street address of this object' EQUALITY caseIgnoreMatch SUBSTR caseIgn
23 oreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
24 olcAttributeTypes: {7}( 2.5.4.10 NAME ( 'o' 'organizationName' ) DESC 'RFC22
25 56: organization this object belongs to' SUP name )
26 olcAttributeTypes: {8}( 2.5.4.11 NAME ( 'ou' 'organizationalUnitName' ) DESC
27 'RFC2256: organizational unit this object belongs to' SUP name )
28 olcAttributeTypes: {9}( 2.5.4.12 NAME 'title' DESC 'RFC2256: title associate
29 d with the entity' SUP name )
30 olcAttributeTypes: {10}( 2.5.4.14 NAME 'searchGuide' DESC 'RFC2256: search g
31 uide, deprecated by enhancedSearchGuide' SYNTAX 1.3.6.1.4.1.1466.115.121.1.
32 25 )
33 olcAttributeTypes: {11}( 2.5.4.15 NAME 'businessCategory' DESC 'RFC2256: bus
34 iness category' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch S
35 YNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
36 olcAttributeTypes: {12}( 2.5.4.16 NAME 'postalAddress' DESC 'RFC2256: postal
37 address' EQUALITY caseIgnoreListMatch SUBSTR caseIgnoreListSubstringsMatch
38 SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )
39 olcAttributeTypes: {13}( 2.5.4.17 NAME 'postalCode' DESC 'RFC2256: postal co
40 de' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.
41 1.4.1.1466.115.121.1.15{40} )
42 olcAttributeTypes: {14}( 2.5.4.18 NAME 'postOfficeBox' DESC 'RFC2256: Post O
43 ffice Box' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX
44 1.3.6.1.4.1.1466.115.121.1.15{40} )
45 olcAttributeTypes: {15}( 2.5.4.19 NAME 'physicalDeliveryOfficeName' DESC 'RF
46 C2256: Physical Delivery Office Name' EQUALITY caseIgnoreMatch SUBSTR caseI
47 gnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
48 olcAttributeTypes: {16}( 2.5.4.20 NAME 'telephoneNumber' DESC 'RFC2256: Tele
49 phone Number' EQUALITY telephoneNumberMatch SUBSTR telephoneNumberSubstring
50 sMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.50{32} )
51 olcAttributeTypes: {17}( 2.5.4.21 NAME 'telexNumber' DESC 'RFC2256: Telex Nu
52 mber' SYNTAX 1.3.6.1.4.1.1466.115.121.1.52 )
53 olcAttributeTypes: {18}( 2.5.4.22 NAME 'teletexTerminalIdentifier' DESC 'RFC
54 2256: Teletex Terminal Identifier' SYNTAX 1.3.6.1.4.1.1466.115.121.1.51 )
55 olcAttributeTypes: {19}( 2.5.4.23 NAME ( 'facsimileTelephoneNumber' 'fax' )
56 DESC 'RFC2256: Facsimile (Fax) Telephone Number' SYNTAX 1.3.6.1.4.1.1466.11
57 5.121.1.22 )
58 olcAttributeTypes: {20}( 2.5.4.24 NAME 'x121Address' DESC 'RFC2256: X.121 Ad
59 dress' EQUALITY numericStringMatch SUBSTR numericStringSubstringsMatch SYNT
60 AX 1.3.6.1.4.1.1466.115.121.1.36{15} )
61 olcAttributeTypes: {21}( 2.5.4.25 NAME 'internationaliSDNNumber' DESC 'RFC22
62 56: international ISDN number' EQUALITY numericStringMatch SUBSTR numericSt
63 ringSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.36{16} )
64 olcAttributeTypes: {22}( 2.5.4.26 NAME 'registeredAddress' DESC 'RFC2256: re
65 gistered postal address' SUP postalAddress SYNTAX 1.3.6.1.4.1.1466.115.121.
66 1.41 )
67 olcAttributeTypes: {23}( 2.5.4.27 NAME 'destinationIndicator' DESC 'RFC2256:
68 destination indicator' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstring
69 sMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.44{128} )
70 olcAttributeTypes: {24}( 2.5.4.28 NAME 'preferredDeliveryMethod' DESC 'RFC22
71 56: preferred delivery method' SYNTAX 1.3.6.1.4.1.1466.115.121.1.14 SINGLE-
72 VALUE )
73 olcAttributeTypes: {25}( 2.5.4.29 NAME 'presentationAddress' DESC 'RFC2256:
74 presentation address' EQUALITY presentationAddressMatch SYNTAX 1.3.6.1.4.1.
75 1466.115.121.1.43 SINGLE-VALUE )
76 olcAttributeTypes: {26}( 2.5.4.30 NAME 'supportedApplicationContext' DESC 'R
77 FC2256: supported application context' EQUALITY objectIdentifierMatch SYNTA
78 X 1.3.6.1.4.1.1466.115.121.1.38 )
79 olcAttributeTypes: {27}( 2.5.4.31 NAME 'member' DESC 'RFC2256: member of a g
80 roup' SUP distinguishedName )
81 olcAttributeTypes: {28}( 2.5.4.32 NAME 'owner' DESC 'RFC2256: owner (of the
82 object)' SUP distinguishedName )
83 olcAttributeTypes: {29}( 2.5.4.33 NAME 'roleOccupant' DESC 'RFC2256: occupan
84 t of role' SUP distinguishedName )
85 olcAttributeTypes: {30}( 2.5.4.36 NAME 'userCertificate' DESC 'RFC2256: X.50
86 9 user certificate, use ;binary' EQUALITY certificateExactMatch SYNTAX 1.3.
87 6.1.4.1.1466.115.121.1.8 )
88 olcAttributeTypes: {31}( 2.5.4.37 NAME 'cACertificate' DESC 'RFC2256: X.509
89 CA certificate, use ;binary' EQUALITY certificateExactMatch SYNTAX 1.3.6.1.
90 4.1.1466.115.121.1.8 )
91 olcAttributeTypes: {32}( 2.5.4.38 NAME 'authorityRevocationList' DESC 'RFC22
92 56: X.509 authority revocation list, use ;binary' SYNTAX 1.3.6.1.4.1.1466.1
93 15.121.1.9 )
94 olcAttributeTypes: {33}( 2.5.4.39 NAME 'certificateRevocationList' DESC 'RFC
95 2256: X.509 certificate revocation list, use ;binary' SYNTAX 1.3.6.1.4.1.14
96 66.115.121.1.9 )
97 olcAttributeTypes: {34}( 2.5.4.40 NAME 'crossCertificatePair' DESC 'RFC2256:
98 X.509 cross certificate pair, use ;binary' SYNTAX 1.3.6.1.4.1.1466.115.121
99 .1.10 )
100 olcAttributeTypes: {35}( 2.5.4.42 NAME ( 'givenName' 'gn' ) DESC 'RFC2256: f
101 irst name(s) for which the entity is known by' SUP name )
102 olcAttributeTypes: {36}( 2.5.4.43 NAME 'initials' DESC 'RFC2256: initials of
103 some or all of names, but not the surname(s).' SUP name )
104 olcAttributeTypes: {37}( 2.5.4.44 NAME 'generationQualifier' DESC 'RFC2256:
105 name qualifier indicating a generation' SUP name )
106 olcAttributeTypes: {38}( 2.5.4.45 NAME 'x500UniqueIdentifier' DESC 'RFC2256:
107 X.500 unique identifier' EQUALITY bitStringMatch SYNTAX 1.3.6.1.4.1.1466.1
108 15.121.1.6 )
109 olcAttributeTypes: {39}( 2.5.4.46 NAME 'dnQualifier' DESC 'RFC2256: DN quali
110 fier' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR case
111 IgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 )
112 olcAttributeTypes: {40}( 2.5.4.47 NAME 'enhancedSearchGuide' DESC 'RFC2256:
113 enhanced search guide' SYNTAX 1.3.6.1.4.1.1466.115.121.1.21 )
114 olcAttributeTypes: {41}( 2.5.4.48 NAME 'protocolInformation' DESC 'RFC2256:
115 protocol information' EQUALITY protocolInformationMatch SYNTAX 1.3.6.1.4.1.
116 1466.115.121.1.42 )
117 olcAttributeTypes: {42}( 2.5.4.50 NAME 'uniqueMember' DESC 'RFC2256: unique
118 member of a group' EQUALITY uniqueMemberMatch SYNTAX 1.3.6.1.4.1.1466.115.1
119 21.1.34 )
120 olcAttributeTypes: {43}( 2.5.4.51 NAME 'houseIdentifier' DESC 'RFC2256: hous
121 e identifier' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYN
122 TAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )
123 olcAttributeTypes: {44}( 2.5.4.52 NAME 'supportedAlgorithms' DESC 'RFC2256:
124 supported algorithms' SYNTAX 1.3.6.1.4.1.1466.115.121.1.49 )
125 olcAttributeTypes: {45}( 2.5.4.53 NAME 'deltaRevocationList' DESC 'RFC2256:
126 delta revocation list; use ;binary' SYNTAX 1.3.6.1.4.1.1466.115.121.1.9 )
127 olcAttributeTypes: {46}( 2.5.4.54 NAME 'dmdName' DESC 'RFC2256: name of DMD'
128 SUP name )
129 olcAttributeTypes: {47}( 2.5.4.65 NAME 'pseudonym' DESC 'X.520(4th): pseudon
130 ym for the object' SUP name )
131 olcAttributeTypes: {48}( 0.9.2342.19200300.100.1.3 NAME ( 'mail' 'rfc822Mail
132 box' ) DESC 'RFC1274: RFC822 Mailbox' EQUALITY caseIgnoreIA5Match SUBST
133 R caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256}
134 )
135 olcAttributeTypes: {49}( 0.9.2342.19200300.100.1.25 NAME ( 'dc' 'domainCompo
136 nent' ) DESC 'RFC1274/2247: domain component' EQUALITY caseIgnoreIA5Match S
137 UBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SIN
138 GLE-VALUE )
139 olcAttributeTypes: {50}( 0.9.2342.19200300.100.1.37 NAME 'associatedDomain'
140 DESC 'RFC1274: domain associated with object' EQUALITY caseIgnoreIA5Match S
141 UBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
142 olcAttributeTypes: {51}( 1.2.840.113549.1.9.1 NAME ( 'email' 'emailAddress'
143 'pkcs9email' ) DESC 'RFC3280: legacy attribute for email addresses in DNs'
144 EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.
145 6.1.4.1.1466.115.121.1.26{128} )
146 olcObjectClasses: {0}( 2.5.6.2 NAME 'country' DESC 'RFC2256: a country' SUP
147 top STRUCTURAL MUST c MAY ( searchGuide $ description ) )
148 olcObjectClasses: {1}( 2.5.6.3 NAME 'locality' DESC 'RFC2256: a locality' SU
149 P top STRUCTURAL MAY ( street $ seeAlso $ searchGuide $ st $ l $ descriptio
150 n ) )
151 olcObjectClasses: {2}( 2.5.6.4 NAME 'organization' DESC 'RFC2256: an organiz
152 ation' SUP top STRUCTURAL MUST o MAY ( userPassword $ searchGuide $ seeAlso
153 $ businessCategory $ x121Address $ registeredAddress $ destinationIndicato
154 r $ preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $ tel
155 ephoneNumber $ internationaliSDNNumber $ facsimileTelephoneNumber $ street
156 $ postOfficeBox $ postalCode $ postalAddress $ physicalDeliveryOfficeName
157 $ st $ l $ description ) )
158 olcObjectClasses: {3}( 2.5.6.5 NAME 'organizationalUnit' DESC 'RFC2256: an o
159 rganizational unit' SUP top STRUCTURAL MUST ou MAY ( userPassword $ searchG
160 uide $ seeAlso $ businessCategory $ x121Address $ registeredAddress $ desti
161 nationIndicator $ preferredDeliveryMethod $ telexNumber $ teletexTerminalId
162 entifier $ telephoneNumber $ internationaliSDNNumber $ facsimileTelephoneNu
163 mber $ street $ postOfficeBox $ postalCode $ postalAddress $ physicalDelive
164 ryOfficeName $ st $ l $ description ) )
165 olcObjectClasses: {4}( 2.5.6.6 NAME 'person' DESC 'RFC2256: a person' SUP to
166 p STRUCTURAL MUST ( sn $ cn ) MAY ( userPassword $ telephoneNumber $ seeAls
167 o $ description ) )
168 olcObjectClasses: {5}( 2.5.6.7 NAME 'organizationalPerson' DESC 'RFC2256: an
169 organizational person' SUP person STRUCTURAL MAY ( title $ x121Address $ r
170 egisteredAddress $ destinationIndicator $ preferredDeliveryMethod $ telexNu
171 mber $ teletexTerminalIdentifier $ telephoneNumber $ internationaliSDNNumbe
172 r $ facsimileTelephoneNumber $ street $ postOfficeBox $ postalCode $ posta
173 lAddress $ physicalDeliveryOfficeName $ ou $ st $ l ) )
174 olcObjectClasses: {6}( 2.5.6.8 NAME 'organizationalRole' DESC 'RFC2256: an o
175 rganizational role' SUP top STRUCTURAL MUST cn MAY ( x121Address $ register
176 edAddress $ destinationIndicator $ preferredDeliveryMethod $ telexNumber $
177 teletexTerminalIdentifier $ telephoneNumber $ internationaliSDNNumber $ fac
178 simileTelephoneNumber $ seeAlso $ roleOccupant $ preferredDeliveryMethod $
179 street $ postOfficeBox $ postalCode $ postalAddress $ physicalDeliveryOffic
180 eName $ ou $ st $ l $ description ) )
181 olcObjectClasses: {7}( 2.5.6.9 NAME 'groupOfNames' DESC 'RFC2256: a group of
182 names (DNs)' SUP top STRUCTURAL MUST ( member $ cn ) MAY ( businessCategor
183 y $ seeAlso $ owner $ ou $ o $ description ) )
184 olcObjectClasses: {8}( 2.5.6.10 NAME 'residentialPerson' DESC 'RFC2256: an r
185 esidential person' SUP person STRUCTURAL MUST l MAY ( businessCategory $ x1
186 21Address $ registeredAddress $ destinationIndicator $ preferredDeliveryMet
187 hod $ telexNumber $ teletexTerminalIdentifier $ telephoneNumber $ internati
188 onaliSDNNumber $ facsimileTelephoneNumber $ preferredDeliveryMethod $ stree
189 t $ postOfficeBox $ postalCode $ postalAddress $ physicalDeliveryOfficeName
190 $ st $ l ) )
191 olcObjectClasses: {9}( 2.5.6.11 NAME 'applicationProcess' DESC 'RFC2256: an
192 application process' SUP top STRUCTURAL MUST cn MAY ( seeAlso $ ou $ l $ de
193 scription ) )
194 olcObjectClasses: {10}( 2.5.6.12 NAME 'applicationEntity' DESC 'RFC2256: an
195 application entity' SUP top STRUCTURAL MUST ( presentationAddress $ cn ) MA
196 Y ( supportedApplicationContext $ seeAlso $ ou $ o $ l $ description ) )
197 olcObjectClasses: {11}( 2.5.6.13 NAME 'dSA' DESC 'RFC2256: a directory syste
198 m agent (a server)' SUP applicationEntity STRUCTURAL MAY knowledgeInformati
199 on )
200 olcObjectClasses: {12}( 2.5.6.14 NAME 'device' DESC 'RFC2256: a device' SUP
201 top STRUCTURAL MUST cn MAY ( serialNumber $ seeAlso $ owner $ ou $ o $ l $
202 description ) )
203 olcObjectClasses: {13}( 2.5.6.15 NAME 'strongAuthenticationUser' DESC 'RFC22
204 56: a strong authentication user' SUP top AUXILIARY MUST userCertificate )
205 olcObjectClasses: {14}( 2.5.6.16 NAME 'certificationAuthority' DESC 'RFC2256
206 : a certificate authority' SUP top AUXILIARY MUST ( authorityRevocationList
207 $ certificateRevocationList $ cACertificate ) MAY crossCertificatePair )
208 olcObjectClasses: {15}( 2.5.6.17 NAME 'groupOfUniqueNames' DESC 'RFC2256: a
209 group of unique names (DN and Unique Identifier)' SUP top STRUCTURAL MUST (
210 uniqueMember $ cn ) MAY ( businessCategory $ seeAlso $ owner $ ou $ o $ de
211 scription ) )
212 olcObjectClasses: {16}( 2.5.6.18 NAME 'userSecurityInformation' DESC 'RFC225
213 6: a user security information' SUP top AUXILIARY MAY ( supportedAlgorithms
214 ) )
215 olcObjectClasses: {17}( 2.5.6.16.2 NAME 'certificationAuthority-V2' SUP cert
216 ificationAuthority AUXILIARY MAY ( deltaRevocationList ) )
217 olcObjectClasses: {18}( 2.5.6.19 NAME 'cRLDistributionPoint' SUP top STRUCTU
218 RAL MUST ( cn ) MAY ( certificateRevocationList $ authorityRevocationList $
219 deltaRevocationList ) )
220 olcObjectClasses: {19}( 2.5.6.20 NAME 'dmd' SUP top STRUCTURAL MUST ( dmdNam
221 e ) MAY ( userPassword $ searchGuide $ seeAlso $ businessCategory $ x121Add
222 ress $ registeredAddress $ destinationIndicator $ preferredDeliveryMethod $
223 telexNumber $ teletexTerminalIdentifier $ telephoneNumber $ internationali
224 SDNNumber $ facsimileTelephoneNumber $ street $ postOfficeBox $ postalCode
225 $ postalAddress $ physicalDeliveryOfficeName $ st $ l $ description ) )
226 olcObjectClasses: {20}( 2.5.6.21 NAME 'pkiUser' DESC 'RFC2587: a PKI user' S
227 UP top AUXILIARY MAY userCertificate )
228 olcObjectClasses: {21}( 2.5.6.22 NAME 'pkiCA' DESC 'RFC2587: PKI certificate
229 authority' SUP top AUXILIARY MAY ( authorityRevocationList $ certificateRe
230 vocationList $ cACertificate $ crossCertificatePair ) )
231 olcObjectClasses: {22}( 2.5.6.23 NAME 'deltaCRL' DESC 'RFC2587: PKI user' SU
232 P top AUXILIARY MAY deltaRevocationList )
233 olcObjectClasses: {23}( 1.3.6.1.4.1.250.3.15 NAME 'labeledURIObject' DESC 'R
234 FC2079: object that contains the URI attribute type' MAY ( labeledURI ) SUP
235 top AUXILIARY )
236 olcObjectClasses: {24}( 0.9.2342.19200300.100.4.19 NAME 'simpleSecurityObjec
237 t' DESC 'RFC1274: simple security object' SUP top AUXILIARY MUST userPasswo
238 rd )
239 olcObjectClasses: {25}( 1.3.6.1.4.1.1466.344 NAME 'dcObject' DESC 'RFC2247:
240 domain component object' SUP top AUXILIARY MUST dc )
241 olcObjectClasses: {26}( 1.3.6.1.1.3.1 NAME 'uidObject' DESC 'RFC2377: uid ob
242 ject' SUP top AUXILIARY MUST uid )
243 structuralObjectClass: olcSchemaConfig
244 entryUUID: 38c549b0-fc43-1036-9076-ebf5d4043f34
245 creatorsName: cn=config
246 createTimestamp: 20170713181706Z
247 entryCSN: 20170713181706.283686Z#000000#000#000000
248 modifiersName: cn=config
249 modifyTimestamp: 20170713181706Z
File tests/ldap/conf.tmpl/cn=config/olcDatabase={-1}frontend.ldif added (mode: 100644) (index 0000000..a408c85)
1 # AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
2 # CRC32 df1076b9
3 dn: olcDatabase={-1}frontend
4 objectClass: olcDatabaseConfig
5 olcDatabase: {-1}frontend
6 structuralObjectClass: olcDatabaseConfig
7 entryUUID: 38c5b350-fc43-1036-9077-ebf5d4043f34
8 creatorsName: cn=config
9 createTimestamp: 20170713181706Z
10 entryCSN: 20170713181706.286424Z#000000#000#000000
11 modifiersName: cn=config
12 modifyTimestamp: 20170713181706Z
File tests/ldap/conf.tmpl/cn=config/olcDatabase={0}config.ldif added (mode: 100644) (index 0000000..f0a5879)
1 # AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
2 # CRC32 c5280e46
3 dn: olcDatabase={0}config
4 objectClass: olcDatabaseConfig
5 olcDatabase: {0}config
6 olcAccess: {0}to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=extern
7 al,cn=auth" manage by * none
8 structuralObjectClass: olcDatabaseConfig
9 entryUUID: 38c5bcba-fc43-1036-9078-ebf5d4043f34
10 creatorsName: cn=config
11 createTimestamp: 20170713181706Z
12 olcRootPW:: YWFhYWFh
13 entryCSN: 20170720195341.940827Z#000000#000#000000
14 modifiersName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
15 modifyTimestamp: 20170720195341Z
File tests/ldap/conf.tmpl/cn=config/olcDatabase={1}monitor.ldif added (mode: 100644) (index 0000000..f0adb4e)
1 # AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
2 # CRC32 1fd30a49
3 dn: olcDatabase={1}monitor
4 objectClass: olcDatabaseConfig
5 olcDatabase: {1}monitor
6 olcAccess: {0}to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=extern
7 al,cn=auth" read by dn.base="cn=Manager,dc=my-domain,dc=com" read by * none
8 structuralObjectClass: olcDatabaseConfig
9 entryUUID: 38c5c732-fc43-1036-9079-ebf5d4043f34
10 creatorsName: cn=config
11 createTimestamp: 20170713181706Z
12 entryCSN: 20170713181706.286941Z#000000#000#000000
13 modifiersName: cn=config
14 modifyTimestamp: 20170713181706Z
File tests/ldap/conf.tmpl/cn=config/olcDatabase={2}mdb.ldif added (mode: 100644) (index 0000000..b21bca5)
1 # AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
2 # CRC32 1d5eab30
3 dn: olcDatabase={2}mdb
4 objectClass: olcDatabaseConfig
5 objectClass: olcMdbConfig
6 olcDatabase: {2}mdb
7 olcSuffix: dc=my-domain,dc=com
8 olcRootDN: cn=Manager,dc=my-domain,dc=com
9 olcDbIndex: objectClass eq,pres
10 olcDbIndex: ou,cn,mail,surname,givenname eq,pres,sub
11 structuralObjectClass: olcMdbConfig
12 entryUUID: 38c5dce0-fc43-1036-907a-ebf5d4043f34
13 creatorsName: cn=config
14 createTimestamp: 20170713181706Z
15 olcDbDirectory: chroot/var/lib/ldap
16 entryCSN: 20170720220913.532403Z#000000#000#000000
17 modifiersName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
18 modifyTimestamp: 20170720220913Z
File tests/ldap/dump-anon.sh added (mode: 100755) (index 0000000..526f546)
1 ldapsearch -v \
2 -x \
3 -LLL \
4 -b "dc=my-domain,dc=com" \
5 -H ldap://localhost:65001 \
6 +
File tests/ldap/dump-slapcat.sh added (mode: 100755) (index 0000000..c5171d9)
1 slapcat -F chroot-s1/etc/openldap/slapd.d
File tests/ldap/dump.sh added (mode: 100755) (index 0000000..318742f)
1
2 ldapsearch -v \
3 -LLL \
4 -b "dc=my-domain,dc=com" \
5 -x \
6 -D "cn=Manager,dc=my-domain,dc=com" \
7 -w 'aaaaaa' \
8 -H ldap://localhost:65001 \
9 memberOf
File tests/ldap/dump_syncrepl_ro.sh added (mode: 100755) (index 0000000..fd6b879)
1 #!/bin/bash
2
3 # http://www.openldap.org/lists/openldap-technical/200909/msg00202.html
4
5 ldapsearch -v \
6 -LLL \
7 -b "dc=my-domain,dc=com" \
8 -x \
9 -D "cn=Manager,dc=my-domain,dc=com" \
10 -w 'aaaaaa' \
11 -H ldap://127.70.247.88:65100 \
12 -s sub \
13 -P 3 \
14 -E '!sync=ro/rid=001,sid=001,csn=20170902202627.782969Z#000000#001#000000;20170902202627.782969Z#000000#001#000000' \
15 "*" +
16
17 # -E '!sync=ro/rid=002,csn=20170902202627.782969Z#000000#001#000000/0' \
18
19 # -E '!sync=ro/rid=001,sid=001,csn=20170902202627.782969Z#000000#001#000000/0' \
File tests/ldap/dump_syncrepl_rp.sh added (mode: 100755) (index 0000000..eac1dec)
1 #!/bin/bash
2
3 # http://www.openldap.org/lists/openldap-technical/200909/msg00202.html
4 # About ContextCSN: http://www.openldap.org/doc/admin23/syncrepl.html
5
6 ldapsearch -v \
7 -LLL \
8 -b "dc=my-domain,dc=com" \
9 -x \
10 -D "cn=Manager,dc=my-domain,dc=com" \
11 -w 'aaaaaa' \
12 -H ldap://localhost:65001 \
13 -s sub \
14 -E 'sync=rp/rid=999,csn=20170903062651.776543Z#000000#001#000000' \
15 "*" +
16
17 -E 'sync=rp/rid=003,csn=20170902202627.782969Z#000000#001#000000;20170902202627.782969Z#000000#001#000000' \
File tests/ldap/get_ContextCSN.sh added (mode: 100644) (index 0000000..3b338ae)
1 #!/bin/bash
2
3 ldapsearch -v \
4 -LLL \
5 -b "dc=my-domain,dc=com" \
6 -x \
7 -D "cn=Manager,dc=my-domain,dc=com" \
8 -w 'aaaaaa' \
9 -H ldap://localhost:65001 \
10 -s base \
11 ContextCSN
File tests/ldap/naming.sh added (mode: 100755) (index 0000000..42b6146)
1 ldapsearch -x -b '' -s base '(objectclass=*)' namingContexts \
2 -H ldapi://ldapi.sock
File tests/ldap/prepare.sh added (mode: 100755) (index 0000000..7069302)
1 #!/bin/bash
2
3 # Wait till the server answers
4 while [ 1 ]; do
5 ldapsearch -x -P3 -s base -H ldap://${rg_ldap_addr}:${rg_ldap_port} &>/dev/null
6 if [ "${?}" != "0" ]; then
7 sleep .1
8 continue
9 fi
10 break
11 done
12
13 # All or nothing
14 set -e
15
16 echo "=== Set path to the database..."
17 cat<<EOF | ldapadd -Y EXTERNAL -H ldapi://ldapi-${rg_ldap_ns}.sock
18 dn: olcDatabase={2}mdb,cn=config
19 changeType: modify
20 replace: olcDbDirectory
21 olcDbDirectory: chroot-${rg_ldap_ns}/var/lib/ldap
22 EOF
23
24
25 # Seems this is not allowed
26 #echo "=== Set log file..."
27 #cat<<EOF | ldapadd -Y EXTERNAL -H ldapi://ldapi-${rg_ldap_ns}.sock
28 #dn: olcDatabase={2}mdb,cn=config
29 #changeType: modify
30 #replace: olcLogFile
31 #olcLogFile: chroot-${rg_ldap_ns}/var/lib/ldap/slapd.log
32 #EOF
33
34
35 echo "=== Copying certificates and keys..."
36 dst="chroot-${rg_ldap_ns}/etc/ssl"
37 mkdir -p "${dst}/certs"
38 cp ../ca/ldap/certs/cacert.pem "${dst}/certs/"
39 cp ../ca/ldap/certs/localhost.pem "chroot-${rg_ldap_ns}/etc/openldap/"
40 cp ../ca/ldap/private/localhost.key "chroot-${rg_ldap_ns}/etc/openldap/"
41
42
43 echo "=== Changing ServerID..."
44 cat <<EOF | ldapmodify -Y EXTERNAL -H ldapi://ldapi-${rg_ldap_ns}.sock
45 dn: cn=config
46 changeType: modify
47 replace: olcServerID
48 olcServerID: ${rg_ldap_server_id}
49 EOF
50
51
52 echo "=== Loading schemas..."
53 for s in cosine nis inetorgperson; do
54 ldapadd -Y EXTERNAL -H ldapi://ldapi-${rg_ldap_ns}.sock \
55 -f /etc/openldap/schema/${s}.ldif
56 done
57
58
59 echo "=== Enabling TLS..."
60 cat<<EOF | ldapmodify -Y EXTERNAL -H ldapi://ldapi-${rg_ldap_ns}.sock
61 dn: cn=config
62 replace: olcTLSCACertificateFile
63 olcTLSCACertificateFile: ${PWD}/chroot-${rg_ldap_ns}/etc/ssl/certs/cacert.pem
64 -
65 replace: olcTLSCertificateKeyFile
66 olcTLSCertificateKeyFile: ${PWD}/chroot-${rg_ldap_ns}/etc/openldap/localhost.key
67 -
68 replace: olcTLSCertificateFile
69 olcTLSCertificateFile: ${PWD}/chroot-${rg_ldap_ns}/etc/openldap/localhost.pem
70 EOF
71
72
73 # http://www.openldap.org/doc/admin24/replication.html#N-Way%20Multi-Master
74 echo "=== Adding syncrepl module and overlay..."
75 cat<<EOF | ldapadd -Y EXTERNAL -H ldapi://ldapi-${rg_ldap_ns}.sock
76 dn: cn=module,cn=config
77 objectClass: olcModuleList
78 cn: module
79 olcModuleLoad: syncprov
80
81 dn: olcOverlay=syncprov,olcDatabase={2}mdb,cn=config
82 objectClass: olcConfig
83 objectClass: olcSyncProvConfig
84 objectClass: olcOverlayConfig
85 objectClass: top
86 olcOverlay: syncprov
87 EOF
88
89
90 echo "=== Adding memberOf module and overlay..."
91 cat<<EOF | ldapadd -Y EXTERNAL -H ldapi://ldapi-${rg_ldap_ns}.sock
92 dn: cn=module,cn=config
93 cn: module
94 objectclass: olcModuleList
95 objectclass: top
96 olcmoduleload: memberof
97
98 dn: olcOverlay=memberof,olcDatabase={2}mdb,cn=config
99 objectClass: olcConfig
100 objectClass: olcMemberOf
101 objectClass: olcOverlayConfig
102 objectClass: top
103 olcOverlay: memberof
104 EOF
105
106
107 echo "=== Adding refInt module and overlay..."
108 cat<<EOF | ldapadd -Y EXTERNAL -H ldapi://ldapi-${rg_ldap_ns}.sock
109 dn: cn=module,cn=config
110 cn: module
111 objectclass: olcModuleList
112 objectclass: top
113 olcmoduleload: refint
114
115 dn: olcOverlay=refint,olcDatabase={2}mdb,cn=config
116 objectClass: olcConfig
117 objectClass: olcOverlayConfig
118 objectClass: olcRefintConfig
119 objectClass: top
120 olcOverlay: refint
121 olcRefintAttribute: memberof member manager owner
122 EOF
123
124
125 cat <<EOF | ldapmodify -Y EXTERNAL -H ldapi://ldapi-${rg_ldap_ns}.sock
126 dn: olcDatabase={2}mdb,cn=config
127 replace: olcRootPW
128 olcRootPW: ${rg_ldap_pass}
129 EOF
130
131
132 if [ "${rg_ldap_producer_url}" != "" ]; then
133 echo "=== We are consumer for ${rg_ldap_producer_url}!"
134 cat <<EOF | ldapmodify -Y EXTERNAL -H ldapi://ldapi-${rg_ldap_ns}.sock
135 dn: olcDatabase={2}mdb,cn=config
136 changeType: modify
137 add: olcLimits
138 olcLimits: dn.exact="cn=Manager,dc=my-domain,dc=com" time.soft=unlimited time.hard=unlimited size.soft=unlimited size.hard=unlimited
139 -
140 add: olcSyncRepl
141 olcSyncRepl: rid=${rg_ldap_producer_rid}
142 provider=${rg_ldap_producer_url}
143 binddn="cn=Manager,dc=my-domain,dc=com"
144 bindmethod=simple
145 credentials=${rg_ldap_pass}
146 searchbase="dc=my-domain,dc=com"
147 type=refreshAndPersist
148 retry="5 5 300 5" timeout=3
149 -
150 add: olcMirrorMode
151 olcMirrorMode: TRUE
152 EOF
153 fi
154
155 if [ "${rg_ldap_add_data}" = "0" ]; then
156 touch "chroot-${rg_ldap_ns}/prep.done"
157 exit 0
158 fi
159
160 cat <<EOF | ldapadd -x -w${rg_ldap_pass} -D "cn=Manager,dc=my-domain,dc=com" -H ldapi://ldapi-${rg_ldap_ns}.sock
161 dn: dc=my-domain,dc=com
162 objectClass: top
163 objectClass: domain
164 dc: my-domain
165
166 dn: cn=Manager,dc=my-domain,dc=com
167 objectClass: organizationalRole
168 cn: Manager
169
170 dn: ou=People,dc=my-domain,dc=com
171 objectClass: organizationalUnit
172 ou: People
173
174 dn: ou=Group,dc=my-domain,dc=com
175 objectClass: organizationalUnit
176 ou: Group
177
178 dn: cn=posix_group1,ou=Group,dc=my-domain,dc=com
179 cn: posix_group1
180 objectClass: top
181 objectClass: posixGroup
182 gidNumber: 100000
183
184 dn: cn=posix_group2,ou=Group,dc=my-domain,dc=com
185 cn: posix_group2
186 objectClass: top
187 objectClass: posixGroup
188 gidNumber: 100001
189
190 dn: uid=user1-${rg_ldap_user_key},ou=People,dc=my-domain,dc=com
191 objectClass: top
192 objectClass: inetOrgPerson
193 objectClass: shadowAccount
194 objectClass: posixAccount
195 uid: user1-${rg_ldap_user_key}
196 userPassword: ${rg_ldap_user_pass}
197 sn: surname-user1-${rg_ldap_user_key}
198 gn: givenname-user1-${rg_ldap_user_key}
199 cn: User1 ${rg_ldap_user_key}
200 uidNumber: 100000
201 gidNumber: 100000
202 mail: user1-${rg_ldap_user_key}@my-domain.com
203 mail: user1-${rg_ldap_user_key}-backup@my-domain.com
204 homeDirectory: /home/user1-${rg_ldap_user_key}
205 description: This is a description of user user1
206
207 dn: uid=user2-${rg_ldap_user_key}-uid,ou=People,dc=my-domain,dc=com
208 objectClass: top
209 objectClass: inetOrgPerson
210 objectClass: shadowAccount
211 objectClass: posixAccount
212 uid: user2-${rg_ldap_user_key}-uid
213 userPassword: ${rg_ldap_user_pass}
214 sn: surname-user2-${rg_ldap_user_key}
215 gn: givenname-user2-${rg_ldap_user_key}
216 cn: User2 ${rg_ldap_user_key}
217 uidNumber: 100001
218 gidNumber: 100001
219 mail: user2-${rg_ldap_user_key}@my-domain.com
220 mail: user2-${rg_ldap_user_key}-backup@my-domain.com
221 homeDirectory: /home/user2-${rg_ldap_user_key}
222 description: user2-${rg_ldap_user_key}
223
224 dn: uid=user3-${rg_ldap_user_key},ou=People,dc=my-domain,dc=com
225 objectClass: top
226 objectClass: inetOrgPerson
227 uid: user3-${rg_ldap_user_key}
228 userPassword: ${rg_ldap_user_pass}
229 sn: surname-user3-${rg_ldap_user_key}
230 cn: User3 ${rg_ldap_user_key}
231 mail: user3-${rg_ldap_user_key}@my-domain.com
232 mail: user3-${rg_ldap_user_key}-backup@my-domain.com
233
234 dn: uid=user4-${rg_ldap_user_key},ou=People,dc=my-domain,dc=com
235 objectClass: top
236 objectClass: inetOrgPerson
237 uid: user4-${rg_ldap_user_key}
238 userPassword: ${rg_ldap_user_pass}
239 sn: surname-user4-${rg_ldap_user_key}
240 gn: givenname-user4-${rg_ldap_user_key}
241 cn: User4 ${rg_ldap_user_key}
242 mail: user4-${rg_ldap_user_key}@my-domain.com
243 mail: user4-${rg_ldap_user_key}-backup@my-domain.com
244
245 # groupOfNames must be created after creating the users, else 'memberOf' will not be set
246 dn: cn=group1,ou=Group,dc=my-domain,dc=com
247 objectClass: top
248 objectClass: groupOfNames
249 cn: group1
250 member: uid=user1-${rg_ldap_user_key},ou=People,dc=my-domain,dc=com
251 member: uid=user2-${rg_ldap_user_key}-uid,ou=People,dc=my-domain,dc=com
252 member: uid=invalid,ou=People,dc=my-domain,dc=com
253
254 dn: cn=group_unique,ou=Group,dc=my-domain,dc=com
255 objectClass: top
256 objectClass: groupOfUniqueNames
257 cn: group_unique
258 uniqueMember: uid=user2-${rg_ldap_user_key}-uid,ou=People,dc=my-domain,dc=com
259 uniqueMember: uid=invalid2,ou=People,dc=my-domain,dc=com
260
261 dn: cn=Admins,ou=Group,dc=my-domain,dc=com
262 objectClass: top
263 objectClass: groupOfNames
264 cn: Admins
265 member: uid=user1-${rg_ldap_user_key},ou=People,dc=my-domain,dc=com
266 EOF
267
268
269 # Signal that preparation is ready
270 touch "chroot-${rg_ldap_ns}/prep.done"
File tests/ldap/start.sh added (mode: 100644) (index 0000000..b70e62c)
1 #!/bin/bash
2
3 # Because we have this in the configuration
4 mkdir -p chroot/var/lib/ldap
5
6 rm -rf chroot-${rg_ldap_ns}
7 mkdir -p chroot-${rg_ldap_ns}/etc/openldap
8
9 cp -a conf.tmpl chroot-${rg_ldap_ns}/etc/openldap/slapd.d
10
11 mkdir -p chroot-${rg_ldap_ns}/var/lib/ldap
12
13 #strace -f -s200 -o slapd.strace \
14 /usr/sbin/slapd \
15 -h "ldap://${rg_ldap_addr}:${rg_ldap_port} ldaps://${rg_ldap_addr}:${rg_ldap_ports} ldapi://ldapi-${rg_ldap_ns}.sock" \
16 -F chroot-${rg_ldap_ns}/etc/openldap/slapd.d \
17 -d -1 &
File tests/ldap_core.php added (mode: 100644) (index 0000000..de85eff)
1 <?php
2 error_reporting(E_ALL | E_STRICT);
3 ini_set('track_errors', 'On');
4
5 $rg_cache_debug = TRUE;
6 $rg_util_debug = TRUE;
7 $rg_sql_debug = 100;
8
9 $INC = dirname(__FILE__) . '/../inc';
10 require_once(dirname(__FILE__) . '/config.php');
11 require_once($INC . '/init.inc.php');
12 require_once($INC . '/util.inc.php');
13 require_once($INC . '/ldap_core.inc.php');
14
15 rg_log_set_file('ldap_core.log');
16
17 $rg_sql = 'host=localhost user=rocketgit dbname=rocketgit connect_timeout=10';
18 $rg_no_db = TRUE;
19 require_once('common.php');
20
21 $_testns = 'admin_ldap_core';
22 $rg_cache_enable = TRUE;
23 $rg_cache_debug = TRUE;
24
25
26 rg_log('');
27 rg_log_enter('Testing ldif2array [1a] (truncated input)...');
28 $r = rg_ldap_core_ldif2array("a: b\nc:");
29 if (($r['ok'] != 1) || ($r['used'] != 0)) {
30 rg_log('Truncated input must return ok(' . $r['ok'] . ') and'
31 . ' used(' . $r['used'] . ') = 0!');
32 exit(1);
33 }
34 rg_log_exit();
35
36
37 rg_log('');
38 rg_log_enter('Testing ldif2array [1b] (no :)...');
39 $r = rg_ldap_core_ldif2array("a b\n\n");
40 if ($r['ok'] == 1) {
41 rg_log('Line without \':\' should not be allowed');
42 exit(1);
43 }
44 rg_log_exit();
45
46
47 rg_log('');
48 rg_log_enter('Testing ldif2array [2]...');
49 $x = @file_get_contents('ldap_core1.ldif');
50 if ($x === FALSE) {
51 rg_log('Cannot load ldap_core1.ldif!');
52 exit(1);
53 }
54 $r = rg_ldap_core_ldif2array($x);
55 rg_log_ml('r: ' . print_r($r, TRUE));
56 if ($r['ok'] != 1) {
57 rg_log('Error parsing ldif: ' . $r['errmsg']);
58 exit(1);
59 }
60 if (@strcmp($r['data'][0]['xxx'], 'my-domain') != 0) {
61 rg_log_ml('r: ' . print_r($r, TRUE));
62 rg_log('data[0][xxx] is not \'my-domain\'!');
63 exit(1);
64 }
65 if (@strcmp($r['data'][2]['dn'], 'ou=People-șț,dc=my-domain,dc=com') != 0) {
66 rg_log_ml('r: ' . print_r($r, TRUE));
67 rg_log('data[2][dn] is not \'ou=People-șț,dc=my-domain,dc=com\'!');
68 exit(1);
69 }
70 rg_log_exit();
71
72
73 rg_log('OK!');
74 ?>
File tests/ldap_core1.ldif added (mode: 100644) (index 0000000..90f4034)
1 dn: dc=my-domain,dc=com
2 objectClass: top
3 objectClass: domain
4 dc: my-domain
5 structuralObjectClass: domain
6 entryUUID: 6126c5ee-2daf-1037-97f6-dbe1554ca9c3
7 creatorsName: cn=Manager,dc=my-domain,dc=com
8 createTimestamp: 20170914154446Z
9 entryCSN: 20170914154446.654363Z#000000#001#000000
10 modifiersName: cn=Manager,dc=my-domain,dc=com
11 modifyTimestamp: 20170914154446Z
12 entryDN: dc=my-domain,dc=com
13 subschemaSubentry: cn=Subschema
14 contextCSN: 20170914154447.363287Z#000000#001#000000
15 hasSubordinates: TRUE
16 xxx:: bXktZG9tYWlu
17 # this is a comment
18
19 dn: cn=Manager,dc=my-domain,dc=com
20 objectClass: organizationalRole
21 cn: Manager
22 structuralObjectClass: organizationalRole
23 entryUUID: 61455cfc-2daf-1037-97f7-dbe1554ca9c3
24 creatorsName: cn=Manager,dc=my-domain,dc=com
25 createTimestamp: 20170914154446Z
26 entryCSN: 20170914154446.854833Z#000000#001#000000
27 modifiersName: cn=Manager,dc=my-domain,dc=com
28 modifyTimestamp: 20170914154446Z
29 entryDN: cn=Manager,dc=my-domain,dc=com
30 subschemaSubentry: cn=Subschema
31 hasSubordinates: FALSE
32
33 dn: ou=People-șț,dc=my-domain,dc=com
34 objectClass: organizationalUnit
35 ou: People
36 structuralObjectClass: organizationalUnit
37 entryUUID: 61691d7c-2daf-1037-97f8-dbe1554ca9c3
38 creatorsName: cn=Manager,dc=my-domain,dc=com
39 createTimestamp: 20170914154447Z
40 entryCSN: 20170914154447.089119Z#000000#001#000000
41 modifiersName: cn=Manager,dc=my-domain,dc=com
42 modifyTimestamp: 20170914154447Z
43 entryDN: ou=People,dc=my-domain,dc=com
44 subschemaSubentry: cn=Subschema
45 hasSubordinates: TRUE
46
File tests/log.php changed (mode: 100644) (index 0d0ed41..99843b7)
... ... rg_log($n);
18 18
19 19 rg_log_ml("Multiline test\nline2\nline3"); rg_log_ml("Multiline test\nline2\nline3");
20 20
21 $c = @file_get_contents('log-' . date('Ymd') . '.log');
22 if ($c === FALSE) {
23 rg_log('Cannot read log content!');
24 exit(1);
25 }
26 $x = explode("\n", $c);
27 // We need only last 4 lines (an older log may be present)
28 // Remove the last one (\n)
29 $c = count($x);
30 unset($x[$c - 1]);
31 $c--;
32
33 while ($c-- > 4)
34 array_shift($x);
35
36 foreach ($x as $i => $v)
37 $x[$i] = substr($v, 20);
38
39 $e = "șacal[0a]\t|Multiline test|line2|line3";
40 $s = implode("|", $x);
41 if (strcmp($s, $e) != 0) {
42 rg_log_ml('x: ' . print_r($x, TRUE));
43 rg_log('[' . $s . '] != [' . $e . ']!');
44 exit(1);
45 }
46
47
48 rg_log('OK!');
21 49 ?> ?>
File tests/repo.php changed (mode: 100644) (index 1d25d4c..b73bac2)
... ... if ($res === FALSE) {
152 152 rg_log("Cannot insert a user uid $uid (" . rg_sql_error() . ")!"); rg_log("Cannot insert a user uid $uid (" . rg_sql_error() . ")!");
153 153 exit(1); exit(1);
154 154 } }
155 rg_sql_free_result($res);
155 156 $rg_ui = rg_user_info($db, $uid, "", ""); $rg_ui = rg_user_info($db, $uid, "", "");
156 157 if ($rg_ui['exists'] != 1) { if ($rg_ui['exists'] != 1) {
157 158 rg_log("Cannot load user info!"); rg_log("Cannot load user info!");
 
... ... if ($res === FALSE) {
173 174 rg_log("Cannot insert user uid $_uid (" . rg_sql_error() . ")!"); rg_log("Cannot insert user uid $_uid (" . rg_sql_error() . ")!");
174 175 exit(1); exit(1);
175 176 } }
177 rg_sql_free_result($res);
176 178 rg_log_exit(); rg_log_exit();
177 179
178 180
File tests/rights.php changed (mode: 100644) (index 5df61ae..1d1fa01)
... ... rg_log_set_file("rights.log");
11 11
12 12 require_once("common.php"); require_once("common.php");
13 13
14 $rg_sql_debug = 1;
15
16 14 // Defaults // Defaults
17 15 $rg_admin_email = "rg@embedromix.ro"; $rg_admin_email = "rg@embedromix.ro";
18 16
File tests/sql-fork.php added (mode: 100644) (index 0000000..65e474d)
1 <?php
2 error_reporting(E_ALL | E_STRICT);
3 ini_set("track_errors", "On");
4
5 $rg_sql_debug = 100;
6
7 $INC = dirname(__FILE__) . '/../inc';
8 require_once(dirname(__FILE__) . '/config.php');
9 require_once($INC . '/init.inc.php');
10 require_once($INC . '/log.inc.php');
11 require_once($INC . '/sql.inc.php');
12
13 rg_log_set_file('sql-fork.log');
14
15 $rg_sql = "host=localhost user=rocketgit dbname=rocketgit connect_timeout=10";
16 $rg_no_db = TRUE;
17 require_once('common.php');
18
19 $sql = 'SELECT 1';
20 $r = rg_sql_query($db, $sql);
21 if ($r === FALSE) {
22 rg_log('Cannot run first query!');
23 exit(1);
24 }
25
26 rg_log('Forking...');
27 $pid = pcntl_fork();
28 if ($pid == 0) {
29 // child
30 rg_log_set_sid(rg_id(6));
31 rg_log('We are the child!');
32 $r = rg_sql_query($db, $sql);
33 if ($r === FALSE) {
34 rg_log('Cannot run query in child!');
35 exit(1);
36 }
37 exit(0);
38 } else if ($pid === -1) {
39 rg_log('Error forking!');
40 } else {
41 // server
42 sleep(1);
43 rg_log('We are the server!');
44 $r = rg_sql_query($db, $sql);
45 if ($r === FALSE) {
46 rg_log('Cannot run query after forking!');
47 exit(1);
48 }
49 }
50
51
52 rg_log("OK!");
53 ?>
File tests/sql.php changed (mode: 100644) (index b7c5c9f..85fa435)
2 2 error_reporting(E_ALL | E_STRICT); error_reporting(E_ALL | E_STRICT);
3 3 ini_set("track_errors", "On"); ini_set("track_errors", "On");
4 4
5 $rg_sql_debug = 100;
6
5 7 $INC = dirname(__FILE__) . "/../inc"; $INC = dirname(__FILE__) . "/../inc";
6 8 require_once(dirname(__FILE__) . "/config.php"); require_once(dirname(__FILE__) . "/config.php");
7 9 require_once($INC . "/init.inc.php"); require_once($INC . "/init.inc.php");
 
... ... rg_log_set_file("sql.log");
12 14
13 15 require_once("common.php"); require_once("common.php");
14 16
15 rg_log("db: drop 'test' table...");
17
18 rg_log('');
19 rg_log_enter('db: drop \'test\' table...');
16 20 $sql = "DROP TABLE IF EXISTS test"; $sql = "DROP TABLE IF EXISTS test";
17 21 $res = rg_sql_query($db, $sql); $res = rg_sql_query($db, $sql);
18 22 if ($res === FALSE) { if ($res === FALSE) {
19 23 rg_log("Cannot create table 'test' (" . rg_sql_error() . ")!"); rg_log("Cannot create table 'test' (" . rg_sql_error() . ")!");
20 24 exit(1); exit(1);
21 25 } }
26 rg_log_exit();
22 27
23 rg_log("db: test creation of a table...");
28
29 rg_log('');
30 rg_log_enter('db: test creation of a table...');
24 31 $sql = "CREATE TABLE test (id TEXT PRIMARY KEY" $sql = "CREATE TABLE test (id TEXT PRIMARY KEY"
25 32 . ", f1 TEXT DEFAULT '', f2 TEXT DEFAULT '')"; . ", f1 TEXT DEFAULT '', f2 TEXT DEFAULT '')";
26 33 $res = rg_sql_query($db, $sql); $res = rg_sql_query($db, $sql);
 
... ... if ($res === FALSE) {
28 35 rg_log("Cannot create table 'test' (" . rg_sql_error() . ")!"); rg_log("Cannot create table 'test' (" . rg_sql_error() . ")!");
29 36 exit(1); exit(1);
30 37 } }
38 rg_log_exit();
39
31 40
32 rg_log("db: test insert...");
41 rg_log('');
42 rg_log_enter('db: test insert...');
33 43 $sql = "INSERT INTO test (id) VALUES ('aaa')"; $sql = "INSERT INTO test (id) VALUES ('aaa')";
34 44 $res = rg_sql_query($db, $sql); $res = rg_sql_query($db, $sql);
35 45 if ($res === FALSE) { if ($res === FALSE) {
36 46 rg_log("Cannot insert!"); rg_log("Cannot insert!");
37 47 exit(1); exit(1);
38 48 } }
49 rg_sql_free_result($res);
50 rg_log_exit();
39 51
40 rg_log("db: test insert with the same key...");
52
53 rg_log('');
54 rg_log_enter('db: test insert with the same key...');
55 // We do not want a err- file to be created
56 $k = md5('Internal error: INSERT INTO test (id) VALUES (\'aaa\'): ERROR: duplicate key value violates unique constraint "test_pkey"' . "\n" . 'DETAIL: Key (id)=(aaa) already exists. (23505)');
57 $rg_error_core_seen[$k] = 1;
41 58 $sql = "INSERT INTO test (id) VALUES ('aaa')"; $sql = "INSERT INTO test (id) VALUES ('aaa')";
42 59 $res = @rg_sql_query($db, $sql); $res = @rg_sql_query($db, $sql);
43 60 if ($res !== FALSE) { if ($res !== FALSE) {
44 61 rg_log("I can do double insert, not good!"); rg_log("I can do double insert, not good!");
45 62 exit(1); exit(1);
46 63 } }
64 unset($rg_error_core_seen[$k]);
65 rg_log_exit();
66
47 67
48 rg_log("db: test delete...");
68 rg_log('');
69 rg_log_enter('db: test delete...');
49 70 $sql = "DELETE FROM test WHERE id = 'aaa'"; $sql = "DELETE FROM test WHERE id = 'aaa'";
50 71 $res = rg_sql_query($db, $sql); $res = rg_sql_query($db, $sql);
51 72 if ($res === FALSE) { if ($res === FALSE) {
52 73 rg_log("Cannot delete!"); rg_log("Cannot delete!");
53 74 exit(1); exit(1);
54 75 } }
76 rg_sql_free_result($res);
77 rg_log_exit();
78
55 79
56 rg_log("db: test prepare with named values...");
80 rg_log('');
81 rg_log_enter('db: test prepare with named values...');
57 82 $sql = "INSERT INTO test(id, f1, f2) VALUES (@@id@@, @@f@@, @@f@@)"; $sql = "INSERT INTO test(id, f1, f2) VALUES (@@id@@, @@f@@, @@f@@)";
58 83 $params = array("id" => "myid", "f" => "value", "junk" => "aaa"); $params = array("id" => "myid", "f" => "value", "junk" => "aaa");
59 84 $res = rg_sql_query_params($db, $sql, $params); $res = rg_sql_query_params($db, $sql, $params);
 
... ... if ($res === FALSE) {
61 86 rg_log("Cannot insert into test using @@x@@!"); rg_log("Cannot insert into test using @@x@@!");
62 87 exit(1); exit(1);
63 88 } }
89 rg_sql_free_result($res);
64 90 $sql = "SELECT * FROM test WHERE id = 'myid'"; $sql = "SELECT * FROM test WHERE id = 'myid'";
65 91 $res = rg_sql_query($db, $sql); $res = rg_sql_query($db, $sql);
66 92 $row = rg_sql_fetch_array($res); $row = rg_sql_fetch_array($res);
 
... ... if (strcmp($row['f1'], "value") != 0) {
68 94 rg_log("Seems that insert with @@x@@ are not working!"); rg_log("Seems that insert with @@x@@ are not working!");
69 95 exit(1); exit(1);
70 96 } }
97 rg_sql_free_result($res);
98 rg_log_exit();
71 99
72 100
73 101 rg_log(''); rg_log('');
 
... ... if (($r === FALSE) || (count($r) != 3) || !isset($r['id'])) {
80 108 } }
81 109 rg_log_exit(); rg_log_exit();
82 110
111
112 rg_log('');
113 rg_log_enter('Testing a unique key violation with ignore...');
114 $ignore = array(RG_SQL_UNIQUE_VIOLATION);
115 $params = array('id' => 'myid', 'f2' => 'bla');
116 $sql = 'INSERT INTO test VALUES (@@id@@, @@f2@@)';
117 $res = rg_sql_query_params_ignore($db, $sql, $params, $ignore, $ignore_kicked);
118 if ($res !== FALSE) {
119 rg_log('res is not false!');
120 exit(1);
121 }
122 if (!strstr($rg_internal_error_last, 'duplicate key value violates unique')) {
123 rg_log('rg_internal_error_last does not contain something'
124 . ' about duplicate key'
125 . ' [' . $rg_internal_error_last . ']!');
126 exit(1);
127 }
128 rg_log_exit();
129
130
83 131 // TODO: test rg_sql_last_id // TODO: test rg_sql_last_id
84 132
85 133 rg_sql_close($db); rg_sql_close($db);
File tests/token.php changed (mode: 100644) (index 1405f79..f605ec3)
... ... $a['token'] = $token;
43 43
44 44 $copy = $a; $copy = $a;
45 45 $copy['token'] = "y" . substr($a['token'], 1); $copy['token'] = "y" . substr($a['token'], 1);
46 // Prevent err- file to be generated
47 $_k = md5('Security violation: invalid token (sign)');
48 $rg_error_core_seen[$_k] = 1;
46 49 $r = rg_token_valid($db, $copy, 'tag2', FALSE); $r = rg_token_valid($db, $copy, 'tag2', FALSE);
47 50 if ($r !== FALSE) { if ($r !== FALSE) {
48 51 rg_log("An altered token must return error!"); rg_log("An altered token must return error!");
File tests/user.php changed (mode: 100644) (index a796078..3180e15)
... ... $_u['session_time'] = 3600;
58 58 $_u['confirm_token'] = ""; $_u['confirm_token'] = "";
59 59 $_u['confirmed'] = 0; $_u['confirmed'] = 0;
60 60 $_u['plan_id'] = 1000; $_u['plan_id'] = 1000;
61 $_u['ask_for_email_confirmation'] = 0;
62 61 $uid = rg_user_edit($db, $_u); $uid = rg_user_edit($db, $_u);
63 62 if ($uid === FALSE) { if ($uid === FALSE) {
64 63 rg_log("Cannot add user (" . rg_user_error() . ")!"); rg_log("Cannot add user (" . rg_user_error() . ")!");
 
... ... $_u['session_time'] = 3600;
186 185 $_u['confirm_token'] = ""; $_u['confirm_token'] = "";
187 186 $_u['confirmed'] = 0; $_u['confirmed'] = 0;
188 187 $_u['plan_id'] = 1000; $_u['plan_id'] = 1000;
189 $_u['ask_for_email_confirmation'] = 0;
190 188 $uid5 = rg_user_edit($db, $_u); $uid5 = rg_user_edit($db, $_u);
191 189 if ($uid5 === FALSE) { if ($uid5 === FALSE) {
192 190 rg_log("Cannot add user5 (" . rg_user_error() . ")!"); rg_log("Cannot add user5 (" . rg_user_error() . ")!");
File tests/util.php changed (mode: 100644) (index 4a7cdec..add0153)
2 2 error_reporting(E_ALL | E_STRICT); error_reporting(E_ALL | E_STRICT);
3 3 ini_set("track_errors", "On"); ini_set("track_errors", "On");
4 4
5 $rg_util_debug = TRUE;
6
5 7 $INC = dirname(__FILE__) . "/../inc"; $INC = dirname(__FILE__) . "/../inc";
6 8 require_once(dirname(__FILE__) . "/config.php"); require_once(dirname(__FILE__) . "/config.php");
7 9 require_once($INC . "/init.inc.php"); require_once($INC . "/init.inc.php");
 
... ... if (strcmp($r, $e) != 0) {
584 586 exit(1); exit(1);
585 587 } }
586 588
589
590 rg_log('');
591 rg_log_enter('rg_exec2');
592 // Define helpers
593 function cb_input($index, &$a, $stream)
594 {
595 rg_log('cb_input[' . $index . '] stream=' . $stream);
596 switch ($stream) {
597 case 1: rg_log(' stdout: ' . $a['in_buf']); break;
598 case 1: rg_log(' stderr: ' . $a['err_buf']); break;
599 }
600
601 $a['out_buf'] .= ' send_something_from_cb_input_' . $index . "\n";
602 }
603 function cb_output($index, &$a)
604 {
605 rg_log('cb_output[' . $index . ']');
606
607 $a['out_buf'] .= ' generated_output_' . $index . "\n";
608
609 // we do not want anymore to be called
610 rg_log('Unsetting cb_output');
611 unset($a['cb_output']);
612 }
613 function cb_error($index, &$a, $msg)
614 {
615 rg_log('cb_error[' . $index . ']: ' . $msg);
616 // If we need to restart the command, use this:
617 //$a['needs_restart'] = TRUE;
618 }
619 function cb_idle($index, &$a)
620 {
621 rg_log('cb_idle[' . $index . ']');
622 $a['done'] = TRUE;
623 }
624 function cb_finish($index, &$a, $exitcode)
625 {
626 rg_log('cb_finish[' . $index . ']: exitcode=' . $exitcode);
627 }
628 function cb_tick(&$a)
629 {
630 rg_log('cb_tick');
631 $a['my'] = 'tick_was_here';
632 }
633
634 $a = array(
635 'cmds' => array(
636 'cmd1' => array(
637 'cmd' => 'echo first1; read a; sleep 2; echo last1; echo "err1-[${a}]" 1>&2',
638 'cb_input' => 'cb_input',
639 'cb_output' => 'cb_output',
640 'cb_error' => 'cb_error',
641 'cb_idle' => 'cb_idle',
642 'cb_finish' => 'cb_finish',
643 'out_buf' => 'aaa1'
644 ),
645 'cmd2' => array(
646 'cmd' => 'echo first2; read a; sleep 2; echo last2; echo "err2-[${a}]" 1>&2',
647 'cb_input' => 'cb_input',
648 'cb_output' => 'cb_output',
649 'cb_error' => 'cb_error',
650 'cb_idle' => 'cb_idle',
651 'cb_finish' => 'cb_finish',
652 'out_buf' => 'aaa2'
653 )
654 ),
655 'cb_tick' => 'cb_tick'
656 );
657 $r = rg_exec2($a);
658 if ($r['ok'] != 1) {
659 rg_log('rg_exec2 failed: ' . $r['errmsg'] . '!');
660 exit(1);
661 }
662 $e = "first1\nlast1\n";
663 if (strcmp($a['cmds']['cmd1']['in_buf'], $e) != 0) {
664 rg_log('cmd1 in_buf is not ok: ['
665 . $a['cmds']['cmd1']['in_buf'] . '] != [' . $e . ']!');
666 exit(1);
667 }
668 $e = "first2\nlast2\n";
669 if (strcmp($a['cmds']['cmd2']['in_buf'], $e) != 0) {
670 rg_log('cmd2 in_buf is not ok: ['
671 . $a['cmds']['cmd2']['in_buf'] . '] != [' . $e . ']!');
672 exit(1);
673 }
674 $e = "err2-[aaa2 generated_output_cmd2]\n";
675 if (strcmp($a['cmds']['cmd2']['err_buf'], $e) != 0) {
676 rg_log('cmd2 err_buf is not ok: ['
677 . $a['cmds']['cmd2']['err_buf'] . '] != [' . $e . ']!');
678 exit(1);
679 }
680 $e = 'tick_was_here';
681 if (!isset($a['my']) || (strcmp($a['my'], $e) != 0)) {
682 rg_log('my is not ok (cb_tick was not called?): ['
683 . (isset($a['my']) ? $a['my'] : '') . '] != [' . $e . ']!');
684 exit(1);
685 }
686 rg_log_exit();
687
688
587 689 rg_log("OK!"); rg_log("OK!");
588 690 ?> ?>
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/catalinux/rocketgit

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/catalinux/rocketgit

Clone this repository using git:
git clone git://git.rocketgit.com/user/catalinux/rocketgit

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main