Line data Source code
1 : /*
2 : * SPDX-License-Identifier: MPL-2.0
3 : *
4 : * This Source Code Form is subject to the terms of the Mozilla Public
5 : * License, v. 2.0. If a copy of the MPL was not distributed with this
6 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 : *
8 : * Copyright 2024 MonetDB Foundation;
9 : * Copyright August 2008 - 2023 MonetDB B.V.;
10 : * Copyright 1997 - July 2008 CWI.
11 : */
12 :
13 : /*
14 : * author Martin Kersten, Fabian Groffen
15 : * Client Management
16 : * Each online client is represented with an entry in the clients table.
17 : * The client may inspect his record at run-time and partially change its properties.
18 : * The administrator sees all client records and has the right to adjust global properties.
19 : */
20 :
21 :
22 : #include "monetdb_config.h"
23 : #include "clients.h"
24 : #include "mcrypt.h"
25 : #include "mal_scenario.h"
26 : #include "mal_instruction.h"
27 : #include "mal_runtime.h"
28 : #include "mal_client.h"
29 : #include "mal_authorize.h"
30 : #include "mal_internal.h"
31 : #include "opt_pipes.h"
32 : #include "gdk_time.h"
33 :
34 : static str
35 1 : CLTsetListing(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
36 : {
37 1 : (void) mb;
38 1 : *getArgReference_int(stk, pci, 0) = cntxt->listing;
39 1 : cntxt->listing = *getArgReference_int(stk, pci, 1);
40 1 : return MAL_SUCCEED;
41 : }
42 :
43 : static str
44 1 : CLTgetClientId(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
45 : {
46 1 : (void) mb;
47 1 : if (cntxt - mal_clients < 0 || cntxt - mal_clients >= MAL_MAXCLIENTS)
48 0 : throw(MAL, "clients.getClientId", "Illegal client index");
49 1 : *getArgReference_int(stk, pci, 0) = (int) (cntxt - mal_clients);
50 1 : return MAL_SUCCEED;
51 : }
52 :
53 : static str
54 0 : CLTgetScenario(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
55 : {
56 0 : (void) mb;
57 0 : if (cntxt->scenario)
58 0 : *getArgReference_str(stk, pci, 0) = GDKstrdup(cntxt->scenario);
59 : else
60 0 : *getArgReference_str(stk, pci, 0) = GDKstrdup("nil");
61 0 : if (*getArgReference_str(stk, pci, 0) == NULL)
62 0 : throw(MAL, "clients.getScenario", SQLSTATE(HY013) MAL_MALLOC_FAIL);
63 : return MAL_SUCCEED;
64 : }
65 :
66 : static str
67 0 : CLTsetScenario(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
68 : {
69 0 : str msg = MAL_SUCCEED;
70 :
71 0 : (void) mb;
72 0 : msg = setScenario(cntxt, *getArgReference_str(stk, pci, 1));
73 0 : *getArgReference_str(stk, pci, 0) = 0;
74 0 : if (msg == NULL) {
75 0 : *getArgReference_str(stk, pci, 0) = GDKstrdup(cntxt->scenario);
76 0 : if (*getArgReference_str(stk, pci, 0) == NULL)
77 0 : throw(MAL, "clients.setScenario", SQLSTATE(HY013) MAL_MALLOC_FAIL);
78 : }
79 : return msg;
80 : }
81 :
82 : static void
83 1 : CLTtimeConvert(time_t l, char *s)
84 : {
85 1 : struct tm localt = (struct tm) { 0 };
86 :
87 1 : (void) localtime_r(&l, &localt);
88 :
89 : #ifdef HAVE_ASCTIME_R3
90 : asctime_r(&localt, s, 26);
91 : #else
92 1 : asctime_r(&localt, s);
93 : #endif
94 1 : s[24] = 0; /* remove newline */
95 1 : }
96 :
97 : static str
98 1 : CLTInfo(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
99 : {
100 1 : bat *ret = getArgReference_bat(stk, pci, 0);
101 1 : bat *ret2 = getArgReference_bat(stk, pci, 1);
102 1 : BAT *b = COLnew(0, TYPE_str, 12, TRANSIENT);
103 1 : BAT *bn = COLnew(0, TYPE_str, 12, TRANSIENT);
104 1 : char buf[32]; /* 32 bytes are enough */
105 :
106 1 : (void) mb;
107 1 : if (b == 0 || bn == 0) {
108 0 : BBPreclaim(b);
109 0 : BBPreclaim(bn);
110 0 : throw(MAL, "clients.info", SQLSTATE(HY013) MAL_MALLOC_FAIL);
111 : }
112 :
113 1 : (void) snprintf(buf, sizeof(buf), "" LLFMT "", (lng) cntxt->user);
114 2 : if (BUNappend(b, "user", false) != GDK_SUCCEED ||
115 1 : BUNappend(bn, buf, false) != GDK_SUCCEED)
116 0 : goto bailout;
117 :
118 2 : if (BUNappend(b, "scenario", false) != GDK_SUCCEED ||
119 1 : BUNappend(bn, cntxt->scenario, false) != GDK_SUCCEED)
120 0 : goto bailout;
121 :
122 1 : (void) snprintf(buf, sizeof(buf), "%d", cntxt->listing);
123 2 : if (BUNappend(b, "listing", false) != GDK_SUCCEED ||
124 1 : BUNappend(bn, buf, false) != GDK_SUCCEED)
125 0 : goto bailout;
126 :
127 1 : CLTtimeConvert(cntxt->login, buf);
128 2 : if (BUNappend(b, "login", false) != GDK_SUCCEED ||
129 1 : BUNappend(bn, buf, false) != GDK_SUCCEED)
130 0 : goto bailout;
131 1 : *ret = b->batCacheid;
132 1 : BBPkeepref(b);
133 1 : *ret2 = bn->batCacheid;
134 1 : BBPkeepref(bn);
135 1 : return MAL_SUCCEED;
136 :
137 0 : bailout:
138 0 : BBPunfix(b->batCacheid);
139 0 : BBPunfix(bn->batCacheid);
140 0 : throw(MAL, "clients.info", SQLSTATE(HY013) MAL_MALLOC_FAIL);
141 : }
142 :
143 : static str
144 0 : CLTLogin(bat *nme, bat *ret)
145 : {
146 0 : BAT *b = COLnew(0, TYPE_str, 12, TRANSIENT);
147 0 : BAT *u = COLnew(0, TYPE_oid, 12, TRANSIENT);
148 0 : int i;
149 0 : char s[32];
150 :
151 0 : if (b == 0 || u == 0)
152 0 : goto bailout;
153 :
154 0 : for (i = 0; i < MAL_MAXCLIENTS; i++) {
155 0 : Client c = mal_clients + i;
156 0 : if (c->mode >= RUNCLIENT && !is_oid_nil(c->user)) {
157 0 : CLTtimeConvert(c->login, s);
158 0 : if (BUNappend(b, s, false) != GDK_SUCCEED ||
159 0 : BUNappend(u, &c->user, false) != GDK_SUCCEED)
160 0 : goto bailout;
161 : }
162 : }
163 0 : *ret = b->batCacheid;
164 0 : BBPkeepref(b);
165 0 : *nme = u->batCacheid;
166 0 : BBPkeepref(u);
167 0 : return MAL_SUCCEED;
168 :
169 0 : bailout:
170 0 : BBPreclaim(b);
171 0 : BBPreclaim(u);
172 0 : throw(MAL, "clients.getLogins", SQLSTATE(HY013) MAL_MALLOC_FAIL);
173 : }
174 :
175 : static str
176 1 : CLTquit(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
177 : {
178 1 : str msg = MAL_SUCCEED;
179 1 : int idx = cntxt->idx;
180 1 : (void) mb; /* fool compiler */
181 :
182 1 : if (pci->argc == 2) {
183 0 : if (cntxt->user == MAL_ADMIN)
184 0 : idx = *getArgReference_int(stk, pci, 1);
185 : else
186 0 : throw(MAL, "clients.quit",
187 : SQLSTATE(42000) "Administrator rights required");
188 : }
189 :
190 1 : if (idx < 0 || idx > MAL_MAXCLIENTS)
191 0 : throw(MAL, "clients.quit", "Illegal session id");
192 :
193 : /* A user can only quit a session under the same id */
194 1 : MT_lock_set(&mal_contextLock);
195 1 : if (mal_clients[idx].mode == FREECLIENT)
196 0 : msg = createException(MAL, "clients.stop",
197 : "Session not active anymore");
198 : else
199 1 : mal_clients[idx].mode = FINISHCLIENT;
200 1 : MT_lock_unset(&mal_contextLock);
201 1 : return msg;
202 : }
203 :
204 : /* Stopping a client in a soft manner by setting the time out marker */
205 : static str
206 0 : CLTstop(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
207 : {
208 0 : int idx = cntxt->idx;
209 0 : str msg = MAL_SUCCEED;
210 :
211 0 : (void) mb;
212 0 : if (cntxt->user != MAL_ADMIN)
213 0 : throw(MAL, "clients.stop",
214 : SQLSTATE(42000) "Administrator rights required");
215 :
216 0 : idx = *getArgReference_int(stk, pci, 1);
217 :
218 0 : if (idx < 0 || idx > MAL_MAXCLIENTS)
219 0 : throw(MAL, "clients.stop", "Illegal session id");
220 :
221 0 : MT_lock_set(&mal_contextLock);
222 0 : if (mal_clients[idx].mode == FREECLIENT)
223 0 : msg = createException(MAL, "clients.stop",
224 : "Session not active anymore");
225 : else
226 0 : mal_clients[idx].qryctx.endtime = 1; /* stop client now */
227 : /* this forces the designated client to stop at the next instruction */
228 0 : MT_lock_unset(&mal_contextLock);
229 0 : return msg;
230 : }
231 :
232 : static str
233 4 : CLTsetoptimizer(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
234 : {
235 4 : int idx = cntxt->idx;
236 4 : str opt, msg = MAL_SUCCEED;
237 :
238 4 : (void) mb;
239 4 : if (pci->argc == 3) {
240 0 : if (cntxt->user == MAL_ADMIN) {
241 0 : idx = *getArgReference_int(stk, pci, 1);
242 0 : opt = *getArgReference_str(stk, pci, 2);
243 : } else {
244 0 : throw(MAL, "clients.setoptimizer",
245 : SQLSTATE(42000) "Administrator rights required");
246 : }
247 : } else {
248 4 : opt = *getArgReference_str(stk, pci, 1);
249 : }
250 :
251 4 : if (idx < 0 || idx > MAL_MAXCLIENTS)
252 0 : throw(MAL, "clients.setoptimizer", "Illegal session id");
253 4 : if (strNil(opt))
254 0 : throw(MAL, "clients.setoptimizer", "Input string cannot be NULL");
255 4 : if (strlen(opt) >= sizeof(mal_clients[idx].optimizer))
256 0 : throw(MAL, "clients.setoptimizer", "Input string is too large");
257 4 : if (!isOptimizerPipe(opt))
258 1 : throw(MAL, "clients.setoptimizer", "Valid optimizer pipe expected");
259 :
260 3 : MT_lock_set(&mal_contextLock);
261 3 : if (mal_clients[idx].mode == FREECLIENT)
262 0 : msg = createException(MAL, "clients.setoptimizer",
263 : "Session not active anymore");
264 : else
265 3 : strcpy_len(mal_clients[idx].optimizer, opt,
266 : sizeof(mal_clients[idx].optimizer));
267 3 : MT_lock_unset(&mal_contextLock);
268 3 : return msg;
269 : }
270 :
271 : static str
272 4 : CLTsetworkerlimit(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
273 : {
274 4 : str msg = MAL_SUCCEED;
275 4 : int idx = cntxt->idx, limit;
276 :
277 4 : (void) mb;
278 4 : if (pci->argc == 3) {
279 0 : if (cntxt->user == MAL_ADMIN) {
280 0 : idx = *getArgReference_int(stk, pci, 1);
281 0 : limit = *getArgReference_int(stk, pci, 2);
282 : } else {
283 0 : throw(MAL, "clients.setworkerlimit",
284 : SQLSTATE(42000) "Administrator rights required");
285 : }
286 : } else {
287 4 : limit = *getArgReference_int(stk, pci, 1);
288 : }
289 :
290 4 : if (idx < 0 || idx > MAL_MAXCLIENTS)
291 0 : throw(MAL, "clients.setworkerlimit", "Illegal session id");
292 4 : if (is_int_nil(limit))
293 0 : throw(MAL, "clients.setworkerlimit",
294 : "The number of workers cannot be NULL");
295 4 : if (limit < 0)
296 1 : throw(MAL, "clients.setworkerlimit",
297 : "The number of workers cannot be negative");
298 :
299 3 : MT_lock_set(&mal_contextLock);
300 3 : if (mal_clients[idx].mode == FREECLIENT)
301 0 : msg = createException(MAL, "clients.setworkerlimit",
302 : "Session not active anymore");
303 : else {
304 3 : if (limit == 0) {
305 0 : if (mal_clients[idx].maxworkers > 0)
306 : limit = mal_clients[idx].maxworkers;
307 3 : } else if (cntxt->user != MAL_ADMIN &&
308 0 : mal_clients[idx].maxworkers > 0 &&
309 : mal_clients[idx].maxworkers < limit) {
310 3 : limit = mal_clients[idx].maxworkers;
311 : }
312 3 : mal_clients[idx].workerlimit = limit;
313 : }
314 3 : MT_lock_unset(&mal_contextLock);
315 3 : return msg;
316 : }
317 :
318 : static str
319 0 : CLTsetmemorylimit(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
320 : {
321 0 : str msg = MAL_SUCCEED;
322 0 : int idx = cntxt->idx, limit;
323 :
324 0 : (void) mb;
325 0 : if (pci->argc == 3) {
326 0 : if (cntxt->user == MAL_ADMIN) {
327 0 : idx = *getArgReference_sht(stk, pci, 1);
328 0 : limit = *getArgReference_int(stk, pci, 2);
329 : } else {
330 0 : throw(MAL, "clients.setmemorylimit",
331 : SQLSTATE(42000) "Administrator rights required");
332 : }
333 : } else {
334 0 : limit = *getArgReference_int(stk, pci, 1);
335 : }
336 :
337 0 : if (idx < 0 || idx > MAL_MAXCLIENTS)
338 0 : throw(MAL, "clients.setmemorylimit", "Illegal session id");
339 0 : if (is_int_nil(limit))
340 0 : throw(MAL, "clients.setmemorylimit",
341 : "The memory limit cannot be NULL");
342 0 : if (limit < 0)
343 0 : throw(MAL, "clients.setmemorylimit",
344 : "The memory limit cannot be negative");
345 :
346 0 : lng mlimit = (lng) limit << 20;
347 :
348 0 : MT_lock_set(&mal_contextLock);
349 0 : if (mal_clients[idx].mode == FREECLIENT)
350 0 : msg = createException(MAL, "clients.setmemorylimit",
351 : "Session not active anymore");
352 : else {
353 0 : if (mlimit == 0) {
354 0 : if (mal_clients[idx].maxmem > 0)
355 : mlimit = mal_clients[idx].maxmem;
356 0 : } else if (cntxt->user != MAL_ADMIN &&
357 0 : mal_clients[idx].maxmem > 0 &&
358 : mal_clients[idx].maxmem < mlimit) {
359 0 : mlimit = mal_clients[idx].maxmem;
360 : }
361 0 : mal_clients[idx].memorylimit = (int) (mlimit >> 20);
362 0 : mal_clients[idx].qryctx.maxmem = (ATOMIC_BASE_TYPE) mlimit;
363 : }
364 0 : MT_lock_unset(&mal_contextLock);
365 0 : return msg;
366 : }
367 :
368 : static str
369 0 : CLTstopSession(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
370 : {
371 0 : str msg = MAL_SUCCEED;
372 0 : int idx = cntxt->idx;
373 0 : (void) mb;
374 :
375 0 : if (cntxt->user != MAL_ADMIN) {
376 0 : throw(MAL, "clients.stopsession",
377 : SQLSTATE(42000) "Administrator rights required");
378 : }
379 0 : idx = *getArgReference_int(stk, pci, 1);
380 0 : if (idx < 0 || idx > MAL_MAXCLIENTS)
381 0 : throw(MAL, "clients.stopSession", "Illegal session id");
382 :
383 0 : MT_lock_set(&mal_contextLock);
384 0 : if (mal_clients[idx].mode == FREECLIENT) {
385 0 : msg = createException(MAL, "clients.stopSession",
386 : "Session not active anymore");
387 : } else {
388 0 : mal_clients[idx].qryctx.endtime = 1; /* stop client now */
389 0 : mal_clients[idx].sessiontimeout = 1; /* stop client session */
390 : }
391 0 : MT_lock_unset(&mal_contextLock);
392 : /* this forces the designated client to stop at the next instruction */
393 0 : return msg;
394 : }
395 :
396 : /* Queries can be temporarily suspended */
397 : static str
398 0 : CLTsuspend(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
399 : {
400 0 : str msg = MAL_SUCCEED;
401 0 : int idx = cntxt->idx;
402 :
403 0 : if (cntxt->user != MAL_ADMIN)
404 0 : throw(MAL, "clients.suspend",
405 : SQLSTATE(42000) "Administrator rights required");
406 :
407 0 : idx = *getArgReference_int(stk, pci, 1);
408 0 : (void) mb;
409 :
410 0 : if (idx < 0 || idx > MAL_MAXCLIENTS)
411 0 : throw(MAL, "clients.suspend", "Illegal session id");
412 :
413 0 : MT_lock_set(&mal_contextLock);
414 0 : if (mal_clients[idx].mode == FREECLIENT)
415 0 : msg = createException(MAL, "clients.suspend",
416 : "Session not active anymore");
417 : else
418 0 : msg = MCsuspendClient(idx);
419 0 : MT_lock_unset(&mal_contextLock);
420 0 : return msg;
421 : }
422 :
423 : static str
424 0 : CLTwakeup(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
425 : {
426 0 : str msg = MAL_SUCCEED;
427 0 : int idx = cntxt->idx;
428 :
429 0 : if (cntxt->user != MAL_ADMIN)
430 0 : throw(MAL, "clients.wakeup",
431 : SQLSTATE(42000) "Administrator rights required");
432 :
433 0 : idx = *getArgReference_int(stk, pci, 1);
434 0 : (void) mb;
435 :
436 0 : if (idx < 0 || idx > MAL_MAXCLIENTS)
437 0 : throw(MAL, "clients.wakeup", "Illegal session id");
438 :
439 0 : MT_lock_set(&mal_contextLock);
440 0 : if (mal_clients[idx].mode == FREECLIENT)
441 0 : msg = createException(MAL, "clients.wakeup",
442 : "Session not active anymore");
443 : else
444 0 : msg = MCawakeClient(idx);
445 0 : MT_lock_unset(&mal_contextLock);
446 0 : return msg;
447 : }
448 :
449 : /* set query timeout based in seconds, converted into microseconds */
450 : static str
451 19 : CLTqueryTimeout(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
452 : {
453 19 : str msg = MAL_SUCCEED;
454 19 : int qto, idx = cntxt->idx;
455 19 : (void) mb;
456 :
457 19 : if (pci->argc == 3) {
458 0 : if (cntxt->user == MAL_ADMIN) {
459 0 : idx = *getArgReference_int(stk, pci, 1);
460 0 : qto = *getArgReference_int(stk, pci, 2);
461 : } else {
462 0 : throw(MAL, "clients.setquerytimeout",
463 : SQLSTATE(42000) "Administrator rights required");
464 : }
465 : } else {
466 19 : qto = *getArgReference_int(stk, pci, 1);
467 : }
468 19 : if (is_int_nil(qto))
469 0 : throw(MAL, "clients.setquerytimeout", "Query timeout cannot be NULL");
470 19 : if (qto < 0)
471 1 : throw(MAL, "clients.setquerytimeout", "Query timeout should be >= 0");
472 :
473 18 : MT_lock_set(&mal_contextLock);
474 18 : if (mal_clients[idx].mode == FREECLIENT)
475 0 : msg = createException(MAL, "clients.setquerytimeout",
476 : "Session not active anymore");
477 : else {
478 : /* when testing (TESTINGMASK), reduce timeout of 1 sec to 1 msec */
479 36 : lng timeout_micro = ATOMIC_GET(&GDKdebug) & TESTINGMASK
480 18 : && qto == 1 ? 1000 : (lng) qto * 1000000;
481 18 : mal_clients[idx].querytimeout = timeout_micro;
482 : }
483 18 : MT_lock_unset(&mal_contextLock);
484 18 : return msg;
485 : }
486 :
487 : // set query timeout based in microseconds
488 : static str
489 2 : CLTqueryTimeoutMicro(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
490 : {
491 2 : str msg = MAL_SUCCEED;
492 2 : int idx = cntxt->idx;
493 2 : lng qto = *getArgReference_lng(stk, pci, 1);
494 2 : (void) mb;
495 :
496 2 : if (is_lng_nil(qto))
497 0 : throw(MAL, "clients.queryTimeout", "Query timeout cannot be NULL");
498 2 : if (qto < 0)
499 0 : throw(MAL, "clients.queryTimeout", "Query timeout should be >= 0");
500 :
501 2 : MT_lock_set(&mal_contextLock);
502 2 : if (mal_clients[idx].mode == FREECLIENT)
503 0 : msg = createException(MAL, "clients.queryTimeout",
504 : "Session not active anymore");
505 : else {
506 2 : mal_clients[idx].querytimeout = qto;
507 2 : QryCtx *qry_ctx = MT_thread_get_qry_ctx();
508 2 : if (qry_ctx) {
509 2 : qry_ctx->endtime = qry_ctx->starttime && qto ? qry_ctx->starttime + qto : 0;
510 : }
511 : }
512 2 : MT_lock_unset(&mal_contextLock);
513 2 : return msg;
514 : }
515 :
516 : /* Set the current session timeout in seconds */
517 : static str
518 2914 : CLTsessionTimeout(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
519 : {
520 2914 : str msg = MAL_SUCCEED;
521 2914 : int sto = -1, idx = cntxt->idx;
522 2914 : (void) mb;
523 :
524 2914 : if (pci->argc == 3) {
525 0 : if (cntxt->user == MAL_ADMIN) {
526 0 : idx = *getArgReference_int(stk, pci, 1);
527 0 : sto = *getArgReference_int(stk, pci, 2);
528 : } else {
529 0 : throw(MAL, "clients.setsessiontimeout",
530 : SQLSTATE(42000) "Administrator rights required");
531 : }
532 : } else {
533 2914 : sto = *getArgReference_int(stk, pci, 1);
534 : }
535 2914 : if (is_int_nil(sto))
536 0 : throw(MAL, "clients.setsessiontimeout",
537 : "Session timeout cannot be NULL");
538 2914 : if (sto < 0)
539 1 : throw(MAL, "clients.setsessiontimeout",
540 : "Session timeout should be >= 0");
541 2913 : if (idx < 0 || idx > MAL_MAXCLIENTS)
542 0 : throw(MAL, "clients.setsessiontimeout", "Illegal session id %d", idx);
543 :
544 2913 : MT_lock_set(&mal_contextLock);
545 2913 : if (mal_clients[idx].mode == FREECLIENT)
546 0 : msg = createException(MAL, "clients.setsessiontimeout",
547 : "Session not active anymore");
548 : else {
549 2913 : mal_clients[idx].sessiontimeout = sto > 0 ? (lng) sto *1000000 + (GDKusec() - mal_clients[idx].session) : 0;
550 2913 : mal_clients[idx].logical_sessiontimeout = (lng) sto;
551 : }
552 2913 : MT_lock_unset(&mal_contextLock);
553 2913 : return msg;
554 : }
555 :
556 : /* Retrieve the session time out */
557 : static str
558 0 : CLTgetProfile(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
559 : {
560 0 : str *opt = getArgReference_str(stk, pci, 0);
561 0 : int *qto = getArgReference_int(stk, pci, 1);
562 0 : int *sto = getArgReference_int(stk, pci, 2);
563 0 : int *wlim = getArgReference_int(stk, pci, 3);
564 0 : int *mlim = getArgReference_int(stk, pci, 4);
565 0 : (void) mb;
566 0 : if (!(*opt = GDKstrdup(cntxt->optimizer)))
567 0 : throw(MAL, "clients.getProfile", SQLSTATE(HY013) MAL_MALLOC_FAIL);
568 0 : *qto = (int) (cntxt->querytimeout / 1000000);
569 0 : *sto = (int) (cntxt->sessiontimeout / 1000000);
570 0 : *wlim = cntxt->workerlimit;
571 0 : *mlim = cntxt->memorylimit;
572 0 : return MAL_SUCCEED;
573 : }
574 :
575 : /* Long running queries are traced in the logger
576 : * with a message from the interpreter.
577 : * This value should be set to minutes to avoid a lengthy log */
578 : static str
579 0 : CLTsetPrintTimeout(void *ret, const int *secs)
580 : {
581 0 : (void) ret;
582 0 : if (is_int_nil(*secs))
583 0 : setqptimeout(0);
584 : else
585 0 : setqptimeout((lng) *secs * 60 * 1000000);
586 0 : return MAL_SUCCEED;
587 : }
588 :
589 : static str
590 14 : CLTmd5sum(str *ret, const char *const *pw)
591 : {
592 14 : if (strNil(*pw)) {
593 1 : *ret = GDKstrdup(str_nil);
594 : } else {
595 13 : char *mret = mcrypt_MD5Sum(*pw, strlen(*pw));
596 :
597 13 : if (!mret)
598 0 : throw(MAL, "clients.md5sum", SQLSTATE(HY013) MAL_MALLOC_FAIL);
599 13 : *ret = GDKstrdup(mret);
600 13 : free(mret);
601 : }
602 14 : if (*ret == NULL)
603 0 : throw(MAL, "clients.md5sum", SQLSTATE(HY013) MAL_MALLOC_FAIL);
604 : return MAL_SUCCEED;
605 : }
606 :
607 : static str
608 1 : CLTsha1sum(str *ret, const char *const *pw)
609 : {
610 1 : if (strNil(*pw)) {
611 0 : *ret = GDKstrdup(str_nil);
612 : } else {
613 1 : char *mret = mcrypt_SHA1Sum(*pw, strlen(*pw));
614 :
615 1 : if (!mret)
616 0 : throw(MAL, "clients.sha1sum", SQLSTATE(HY013) MAL_MALLOC_FAIL);
617 1 : *ret = GDKstrdup(mret);
618 1 : free(mret);
619 : }
620 1 : if (*ret == NULL)
621 0 : throw(MAL, "clients.sha1sum", SQLSTATE(HY013) MAL_MALLOC_FAIL);
622 : return MAL_SUCCEED;
623 : }
624 :
625 : static str
626 1 : CLTripemd160sum(str *ret, const char *const *pw)
627 : {
628 1 : if (strNil(*pw)) {
629 0 : *ret = GDKstrdup(str_nil);
630 : } else {
631 1 : char *mret = mcrypt_RIPEMD160Sum(*pw, strlen(*pw));
632 :
633 1 : if (!mret)
634 0 : throw(MAL, "clients.ripemd160sum", SQLSTATE(HY013) MAL_MALLOC_FAIL);
635 1 : *ret = GDKstrdup(mret);
636 1 : free(mret);
637 : }
638 1 : if (*ret == NULL)
639 0 : throw(MAL, "clients.ripemd160sum", SQLSTATE(HY013) MAL_MALLOC_FAIL);
640 : return MAL_SUCCEED;
641 : }
642 :
643 : static str
644 4 : CLTsha2sum(str *ret, const char *const *pw, const int *bits)
645 : {
646 8 : if (strNil(*pw) || is_int_nil(*bits)) {
647 0 : *ret = GDKstrdup(str_nil);
648 : } else {
649 4 : char *mret = 0;
650 4 : switch (*bits) {
651 1 : case 512:
652 1 : mret = mcrypt_SHA512Sum(*pw, strlen(*pw));
653 1 : break;
654 1 : case 384:
655 1 : mret = mcrypt_SHA384Sum(*pw, strlen(*pw));
656 1 : break;
657 1 : case 256:
658 1 : mret = mcrypt_SHA256Sum(*pw, strlen(*pw));
659 1 : break;
660 1 : case 224:
661 1 : mret = mcrypt_SHA224Sum(*pw, strlen(*pw));
662 1 : break;
663 0 : default:
664 0 : (void) mret;
665 0 : throw(ILLARG, "clients.sha2sum", "wrong number of bits "
666 : "for SHA2 sum: %d", *bits);
667 : }
668 4 : if (!mret)
669 0 : throw(MAL, "clients.sha2sum", SQLSTATE(HY013) MAL_MALLOC_FAIL);
670 4 : *ret = GDKstrdup(mret);
671 4 : free(mret);
672 : }
673 4 : if (*ret == NULL)
674 0 : throw(MAL, "clients.sha2sum", SQLSTATE(HY013) MAL_MALLOC_FAIL);
675 : return MAL_SUCCEED;
676 : }
677 :
678 : static str
679 0 : CLTbackendsum(str *ret, const char *const *pw)
680 : {
681 0 : if (strNil(*pw)) {
682 0 : *ret = GDKstrdup(str_nil);
683 : } else {
684 0 : char *mret = mcrypt_BackendSum(*pw, strlen(*pw));
685 0 : if (mret == NULL)
686 0 : throw(MAL, "clients.backendsum", SQLSTATE(HY013) MAL_MALLOC_FAIL);
687 0 : *ret = GDKstrdup(mret);
688 0 : free(mret);
689 : }
690 0 : if (*ret == NULL)
691 0 : throw(MAL, "clients.backendsum", SQLSTATE(HY013) MAL_MALLOC_FAIL);
692 : return MAL_SUCCEED;
693 : }
694 :
695 : static str
696 5 : CLTgetUsername(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
697 : {
698 5 : str *ret = getArgReference_str(stk, pci, 0);
699 5 : (void) mb;
700 :
701 5 : *ret = GDKstrdup(cntxt->username);
702 5 : return MAL_SUCCEED;
703 : }
704 :
705 : static str
706 0 : CLTgetPasswordHash(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
707 : {
708 0 : (void) cntxt;
709 0 : (void) mb;
710 0 : (void) stk;
711 0 : (void) pci;
712 :
713 0 : throw(MAL, "clients.getPassword",
714 : SQLSTATE(0A000) PROGRAM_NYI);
715 : }
716 :
717 : static str
718 0 : CLTcheckPermission(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
719 : {
720 0 : (void) cntxt;
721 0 : (void) mb;
722 0 : (void) stk;
723 0 : (void) pci;
724 :
725 0 : throw(MAL, "clients.checkPermission",
726 : SQLSTATE(0A000) PROGRAM_NYI);
727 : }
728 :
729 : str
730 2 : CLTshutdown(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
731 : {
732 2 : str *ret = getArgReference_str(stk, pci, 0);
733 2 : int delay;
734 2 : bit force = FALSE;
735 2 : int leftover;
736 2 : char buf[1024] = { "safe to stop last connection" };
737 :
738 2 : if (pci->argc == 3)
739 1 : force = *getArgReference_bit(stk, pci, 2);
740 :
741 2 : (void) mb;
742 :
743 2 : delay = *getArgReference_bte(stk, pci, 1);
744 :
745 2 : if (cntxt->user != MAL_ADMIN)
746 0 : throw(MAL, "mal.shutdown",
747 : SQLSTATE(42000) "Administrator rights required");
748 2 : if (is_int_nil(delay))
749 : throw(MAL, "mal.shutdown", "Delay cannot be NULL");
750 2 : if (delay < 0)
751 0 : throw(MAL, "mal.shutdown", "Delay cannot be negative");
752 2 : if (is_bit_nil(force))
753 0 : throw(MAL, "mal.shutdown", "Force cannot be NULL");
754 2 : MCstopClients(cntxt);
755 2 : do {
756 2 : if ((leftover = MCactiveClients() - 1))
757 0 : MT_sleep_ms(1000);
758 2 : delay--;
759 2 : } while (delay > 0 && leftover > 1);
760 2 : if (delay == 0 && leftover > 1)
761 0 : snprintf(buf, 1024, "%d client sessions still running", leftover);
762 2 : *ret = GDKstrdup(buf);
763 2 : if (force)
764 1 : GDKprepareExit();
765 2 : if (*ret == NULL)
766 0 : throw(MAL, "mal.shutdown", SQLSTATE(HY013) MAL_MALLOC_FAIL);
767 : return MAL_SUCCEED;
768 : }
769 :
770 : static str
771 15 : CLTgetSessionID(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
772 : {
773 15 : (void) mb;
774 15 : (void) stk;
775 15 : (void) pci;
776 15 : *getArgReference_int(stk, pci, 0) = cntxt->idx;
777 15 : return MAL_SUCCEED;
778 : }
779 :
780 : static str
781 4 : CLTsetClientInfo(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
782 : {
783 4 : (void)mb;
784 4 : str property = *getArgReference_str(stk, pci, 1);
785 4 : str value = *getArgReference_str(stk, pci, 2);
786 :
787 4 : MCsetClientInfo(cntxt, property, value);
788 4 : return MAL_SUCCEED;
789 : }
790 :
791 : #include "mel.h"
792 : mel_func clients_init_funcs[] = {
793 : pattern("clients", "setListing", CLTsetListing, true, "Turn on/off echo of MAL instructions:\n1 - echo input,\n2 - show mal instruction,\n4 - show details of type resolutoin, \n8 - show binding information.", args(1,2, arg("",int),arg("flag",int))),
794 : pattern("clients", "getId", CLTgetClientId, false, "Return a number that uniquely represents the current client.", args(1,1, arg("",int))),
795 : pattern("clients", "getInfo", CLTInfo, false, "Pseudo bat with client attributes.", args(2,2, batarg("",str),batarg("",str))),
796 : pattern("clients", "getScenario", CLTgetScenario, false, "Retrieve current scenario name.", args(1,1, arg("",str))),
797 : pattern("clients", "setScenario", CLTsetScenario, true, "Switch to other scenario handler, return previous one.", args(1,2, arg("",str),arg("msg",str))),
798 : pattern("clients", "quit", CLTquit, true, "Terminate the client session.", args(1,1, arg("",void))),
799 : pattern("clients", "quit", CLTquit, true, "Terminate the session for a single client using a soft error.\nIt is the privilege of the console user.", args(1,2, arg("",void),arg("idx",int))),
800 : command("clients", "getLogins", CLTLogin, false, "Pseudo bat of client id and login time.", args(2,2, batarg("user",oid),batarg("start",str))),
801 : pattern("clients", "stop", CLTstop, true, "Stop the query execution at the next eligible statement.", args(0,1, arg("id",int))),
802 : pattern("clients", "suspend", CLTsuspend, true, "Put a client process to sleep for some time.\nIt will simple sleep for a second at a time, until\nthe awake bit has been set in its descriptor", args(1,2, arg("",void),arg("id",int))),
803 : pattern("clients", "wakeup", CLTwakeup, true, "Wakeup a client process", args(1,2, arg("",void),arg("id",int))),
804 : pattern("clients", "getprofile", CLTgetProfile, false, "Retrieve the profile settings for a client", args(5,5, arg("opt",str),arg("q",int),arg("s",int),arg("w",int),arg("m",int))),
805 : pattern("clients", "setQryTimeoutMicro", CLTqueryTimeoutMicro, true, "", args(1,2, arg("",void),arg("n",lng))),
806 : pattern("clients", "setquerytimeout", CLTqueryTimeout, true, "", args(1,2, arg("",void),arg("n",int))),
807 : pattern("clients", "setquerytimeout", CLTqueryTimeout, true, "A query is aborted after q seconds (q=0 means run undisturbed).", args(1,3, arg("",void),arg("sid",int),arg("n",int))),
808 : pattern("clients", "setsessiontimeout", CLTsessionTimeout, true, "", args(1,2, arg("",void),arg("n",int))),
809 : pattern("clients", "setsessiontimeout", CLTsessionTimeout, true, "Set the session timeout for a particulat session id", args(1,3, arg("",void),arg("sid",int),arg("n",int))),
810 : pattern("clients", "setoptimizer", CLTsetoptimizer, true, "", args(1,2, arg("",void),arg("opt",str))),
811 : pattern("clients", "setoptimizer", CLTsetoptimizer, true, "Set the session optimizer", args(1,3, arg("",void),arg("sid",int),arg("opt",str))),
812 : pattern("clients", "setworkerlimit", CLTsetworkerlimit, true, "", args(1,2, arg("",void),arg("n",int))),
813 : pattern("clients", "setworkerlimit", CLTsetworkerlimit, true, "Limit the number of worker threads per query", args(1,3, arg("",void),arg("sid",int),arg("n",int))),
814 : pattern("clients", "setmemorylimit", CLTsetmemorylimit, true, "", args(1,2, arg("",void),arg("n",int))),
815 : pattern("clients", "setmemorylimit", CLTsetmemorylimit, true, "Limit the memory claim in MB per query", args(1,3, arg("",void),arg("sid",int),arg("n",int))),
816 : pattern("clients", "stopsession", CLTstopSession, true, "Stop a particular session", args(1,2, arg("",void),arg("sid",int))),
817 : command("clients", "setprinttimeout", CLTsetPrintTimeout, true, "Print running query every so many seconds.", args(1,2, arg("",void),arg("n",int))),
818 : pattern("clients", "shutdown", CLTshutdown, true, "", args(1,2, arg("",str),arg("delay",bte))),
819 : pattern("clients", "shutdown", CLTshutdown, true, "Close all other client connections. Return if it succeeds.\nIf forced is set then always stop the system the hard way", args(1,3, arg("",str),arg("delay",bte),arg("forced",bit))),
820 : command("clients", "md5sum", CLTmd5sum, false, "Return hex string representation of the MD5 hash of the given string", args(1,2, arg("",str),arg("pw",str))),
821 : command("clients", "sha1sum", CLTsha1sum, false, "Return hex string representation of the SHA-1 hash of the given string", args(1,2, arg("",str),arg("pw",str))),
822 : command("clients", "sha2sum", CLTsha2sum, false, "Return hex string representation of the SHA-2 hash with bits of the given string", args(1,3, arg("",str),arg("pw",str),arg("bits",int))),
823 : command("clients", "ripemd160sum", CLTripemd160sum, false, "Return hex string representation of the RIPEMD160 hash of the given string", args(1,2, arg("",str),arg("pw",str))),
824 : command("clients", "backendsum", CLTbackendsum, false, "Return hex string representation of the currently used hash of the given string", args(1,2, arg("",str),arg("pw",str))),
825 : pattern("clients", "getUsername", CLTgetUsername, false, "Return the username of the currently logged in user", args(1,1, arg("",str))),
826 : pattern("clients", "getPasswordHash", CLTgetPasswordHash, false, "Return the password hash of the given user", args(1,2, arg("",str),arg("user",str))),
827 : pattern("clients", "checkPermission", CLTcheckPermission, false, "Check permission for a user, requires hashed password (backendsum)", args(1,3, arg("",void),arg("usr",str),arg("pw",str))),
828 : pattern("clients", "current_sessionid", CLTgetSessionID, false, "return current session ID", args(1,1, arg("",int))),
829 : pattern("clients", "setinfo", CLTsetClientInfo, true, "set a clientinfo property", args(1, 3, arg("",str), arg("property", str), arg("value", str))),
830 : { .imp=NULL }
831 : };
832 : #include "mal_import.h"
833 : #ifdef _MSC_VER
834 : #undef read
835 : #pragma section(".CRT$XCU",read)
836 : #endif
837 325 : LIB_STARTUP_FUNC(init_clients_mal)
838 325 : { mal_module("clients", NULL, clients_init_funcs); }
|