]>
Commit | Line | Data |
---|---|---|
7ac48069 | 1 | /* $Id$ |
73cf66ba | 2 | * |
7ac48069 | 3 | * Check access to queries |
73cf66ba | 4 | * |
7ac48069 | 5 | * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology |
6 | * For copying and distribution information, please see the file | |
7 | * <mit-copyright.h>. | |
73cf66ba | 8 | */ |
9 | ||
73cf66ba | 10 | #include <mit-copyright.h> |
73cf66ba | 11 | #include "mr_server.h" |
7ac48069 | 12 | #include "qrtn.h" |
03c05291 | 13 | #include "query.h" |
7ac48069 | 14 | |
73cf66ba | 15 | #include <ctype.h> |
7ac48069 | 16 | #include <stdlib.h> |
17 | ||
73cf66ba | 18 | EXEC SQL INCLUDE sqlca; |
7ac48069 | 19 | |
20 | RCSID("$Header$"); | |
73cf66ba | 21 | |
22 | extern char *whoami; | |
03c05291 | 23 | extern int dbms_errno, mr_errcode; |
73cf66ba | 24 | |
03c05291 | 25 | EXEC SQL WHENEVER SQLERROR DO dbmserr(); |
73cf66ba | 26 | |
27 | ||
28 | /* Specialized Access Routines */ | |
29 | ||
30 | /* access_user - verify that client name equals specified login name | |
31 | * | |
32 | * - since field validation routines are called first, a users_id is | |
33 | * now in argv[0] instead of the login name. | |
34 | */ | |
35 | ||
5eaef520 | 36 | int access_user(struct query *q, char *argv[], client *cl) |
73cf66ba | 37 | { |
5eaef520 | 38 | if (cl->users_id != *(int *)argv[0]) |
39 | return MR_PERM; | |
40 | else | |
41 | return MR_SUCCESS; | |
73cf66ba | 42 | } |
43 | ||
44 | ||
45 | ||
46 | /* access_login - verify that client name equals specified login name | |
47 | * | |
48 | * argv[0...n] contain search info. q-> | |
49 | */ | |
50 | ||
5eaef520 | 51 | int access_login(struct query *q, char *argv[], client *cl) |
73cf66ba | 52 | { |
5eaef520 | 53 | EXEC SQL BEGIN DECLARE SECTION; |
54 | int id; | |
55 | EXEC SQL END DECLARE SECTION; | |
73cf66ba | 56 | |
5eaef520 | 57 | if (q->argc != 1) |
58 | return MR_ARGS; | |
03c05291 | 59 | |
5eaef520 | 60 | if (!strcmp(q->shortname, "gual")) |
61 | { | |
5906749e | 62 | EXEC SQL SELECT users_id INTO :id FROM users |
cc0ec904 | 63 | WHERE login = :argv[0] AND users_id != 0; |
5eaef520 | 64 | } |
65 | else if (!strcmp(q->shortname, "gubl")) | |
66 | { | |
03c05291 | 67 | EXEC SQL SELECT users_id INTO :id FROM users u |
cc0ec904 | 68 | WHERE u.login = :argv[0] AND u.users_id != 0; |
5eaef520 | 69 | } |
70 | else if (!strcmp(q->shortname, "guau")) | |
71 | { | |
5906749e | 72 | EXEC SQL SELECT users_id INTO :id FROM users |
73 | WHERE unix_uid = :argv[0] AND users_id != 0; | |
5eaef520 | 74 | } |
75 | else if (!strcmp(q->shortname, "gubu")) | |
76 | { | |
03c05291 | 77 | EXEC SQL SELECT users_id INTO :id FROM users u |
78 | WHERE u.unix_uid = :argv[0] AND u.users_id != 0; | |
73cf66ba | 79 | } |
80 | ||
5eaef520 | 81 | if (sqlca.sqlcode == SQL_NO_MATCH) |
82 | return MR_NO_MATCH; /* ought to be MR_USER, but this is what | |
83 | gual returns, so we have to be consistent */ | |
84 | else if (sqlca.sqlerrd[2] != 1 || id != cl->users_id) | |
85 | return MR_PERM; | |
86 | else | |
87 | return MR_SUCCESS; | |
73cf66ba | 88 | } |
89 | ||
90 | ||
f659afb2 | 91 | /* access_spob - check access for set_pobox */ |
92 | ||
93 | int access_spob(struct query *q, char *argv[], client *cl) | |
94 | { | |
51e578b6 | 95 | EXEC SQL BEGIN DECLARE SECTION; |
96 | int id; | |
97 | EXEC SQL END DECLARE SECTION; | |
98 | ||
99 | if (!strcmp(argv[1], "IMAP")) | |
100 | { | |
101 | EXEC SQL SELECT owner INTO :id FROM filesys f | |
102 | WHERE f.label = :argv[2] AND f.type = 'IMAP' AND | |
103 | f.lockertype = 'USER'; | |
104 | if (cl->users_id != id) | |
105 | return MR_PERM; | |
106 | } | |
107 | if (cl->users_id != *(int *)argv[0]) | |
f659afb2 | 108 | return MR_PERM; |
109 | else | |
110 | return MR_SUCCESS; | |
111 | } | |
112 | ||
73cf66ba | 113 | |
114 | /* access_list - check access for most list operations | |
115 | * | |
116 | * Inputs: argv[0] - list_id | |
117 | * q - query name | |
118 | * argv[2] - member ID (only for queries "amtl" and "dmfl") | |
e688520a | 119 | * argv[7] - group ID (only for query "ulis") |
73cf66ba | 120 | * cl - client name |
121 | * | |
122 | * - check that client is a member of the access control list | |
123 | * - OR, if the query is add_member_to_list or delete_member_from_list | |
124 | * and the list is public, allow access if client = member | |
125 | */ | |
126 | ||
5eaef520 | 127 | int access_list(struct query *q, char *argv[], client *cl) |
73cf66ba | 128 | { |
5eaef520 | 129 | EXEC SQL BEGIN DECLARE SECTION; |
130 | int list_id, acl_id, flags, gid, users_id; | |
e688520a | 131 | char acl_type[LIST_ACL_TYPE_SIZE], name[LIST_NAME_SIZE], *newname; |
5eaef520 | 132 | EXEC SQL END DECLARE SECTION; |
133 | int status; | |
134 | ||
135 | list_id = *(int *)argv[0]; | |
17f090e1 | 136 | EXEC SQL SELECT acl_id, acl_type, gid, publicflg, name |
137 | INTO :acl_id, :acl_type, :gid, :flags, :name | |
5eaef520 | 138 | FROM list |
139 | WHERE list_id = :list_id; | |
140 | ||
141 | if (sqlca.sqlerrd[2] != 1) | |
142 | return MR_INTERNAL; | |
143 | ||
ae4cbe3d | 144 | /* Allow client to add self to public list or delete self from any |
145 | * list. | |
146 | */ | |
147 | if ((((!strcmp("amtl", q->shortname) || | |
148 | !strcmp("atml", q->shortname)) && flags) || | |
5eaef520 | 149 | (!strcmp("dmfl", q->shortname)))) |
150 | { | |
151 | if (!strcmp("USER", argv[1]) && *(int *)argv[2] == cl->users_id) | |
152 | return MR_SUCCESS; | |
153 | if (!strcmp("KERBEROS", argv[1]) && *(int *)argv[2] == -cl->client_id) | |
154 | return MR_SUCCESS; | |
155 | } /* if update_list, don't allow them to change the GID or rename to | |
156 | a username other than their own */ | |
157 | else if (!strcmp("ulis", q->shortname)) | |
158 | { | |
159 | if (!strcmp(argv[7], UNIQUE_GID)) | |
160 | { | |
161 | if (gid != -1) | |
162 | return MR_PERM; | |
163 | } | |
164 | else | |
165 | { | |
166 | if (gid != atoi(argv[7])) | |
167 | return MR_PERM; | |
168 | } | |
5c96d2cd | 169 | |
d83ee5a2 | 170 | newname = argv[1]; |
5c96d2cd | 171 | |
172 | if (!strcmp("ulis", q->shortname)) | |
173 | { | |
174 | /* Check that it doesn't conflict with the Grouper namespace. */ | |
175 | if (strlen(newname) > 4 && isdigit(newname[2]) && | |
176 | isdigit(newname[3]) && newname[4] == '-') | |
177 | { | |
178 | if (!strncasecmp(newname, "fa", 2) || | |
179 | !strncasecmp(newname, "sp", 2) || | |
180 | !strncasecmp(newname, "su", 2) || | |
181 | !strncasecmp(newname, "ja", 2)) | |
182 | return MR_RESERVED; | |
183 | } | |
184 | ||
185 | /* Don't let anyone take owner-foo list names. They interact | |
186 | * weirdly with the aliases automatically generated by | |
187 | * mailhub.gen. | |
188 | */ | |
189 | if (!strncasecmp(newname, "owner-", 6)) | |
190 | return MR_RESERVED; | |
191 | } | |
192 | ||
d83ee5a2 | 193 | EXEC SQL SELECT users_id INTO :users_id FROM users |
5eaef520 | 194 | WHERE login = :newname; |
17f090e1 | 195 | if ((sqlca.sqlcode != SQL_NO_MATCH) && strcmp(strtrim(name), newname) && |
196 | (users_id != cl->users_id)) | |
5eaef520 | 197 | return MR_PERM; |
73cf66ba | 198 | } |
199 | ||
5eaef520 | 200 | /* check for client in access control list */ |
201 | status = find_member(acl_type, acl_id, cl); | |
202 | if (!status) | |
203 | return MR_PERM; | |
73cf66ba | 204 | |
5eaef520 | 205 | return MR_SUCCESS; |
73cf66ba | 206 | } |
207 | ||
208 | ||
209 | /* access_visible_list - allow access to list only if it is not hidden, | |
210 | * or if the client is on the ACL | |
211 | * | |
212 | * Inputs: argv[0] - list_id | |
213 | * cl - client identifier | |
214 | */ | |
215 | ||
5eaef520 | 216 | int access_visible_list(struct query *q, char *argv[], client *cl) |
73cf66ba | 217 | { |
5eaef520 | 218 | EXEC SQL BEGIN DECLARE SECTION; |
219 | int list_id, acl_id, flags ; | |
e688520a | 220 | char acl_type[LIST_ACL_TYPE_SIZE]; |
5eaef520 | 221 | EXEC SQL END DECLARE SECTION; |
222 | int status; | |
223 | ||
224 | list_id = *(int *)argv[0]; | |
225 | EXEC SQL SELECT hidden, acl_id, acl_type | |
226 | INTO :flags, :acl_id, :acl_type | |
227 | FROM list | |
228 | WHERE list_id = :list_id; | |
229 | if (sqlca.sqlerrd[2] != 1) | |
230 | return MR_INTERNAL; | |
231 | if (!flags) | |
232 | return MR_SUCCESS; | |
233 | ||
234 | /* check for client in access control list */ | |
235 | status = find_member(acl_type, acl_id, cl); | |
236 | if (!status) | |
237 | return MR_PERM; | |
238 | ||
239 | return MR_SUCCESS; | |
73cf66ba | 240 | } |
241 | ||
242 | ||
243 | /* access_vis_list_by_name - allow access to list only if it is not hidden, | |
244 | * or if the client is on the ACL | |
245 | * | |
246 | * Inputs: argv[0] - list name | |
247 | * cl - client identifier | |
248 | */ | |
249 | ||
5eaef520 | 250 | int access_vis_list_by_name(struct query *q, char *argv[], client *cl) |
73cf66ba | 251 | { |
5eaef520 | 252 | EXEC SQL BEGIN DECLARE SECTION; |
253 | int acl_id, flags, rowcount; | |
e688520a | 254 | char acl_type[LIST_ACL_TYPE_SIZE], *listname; |
5eaef520 | 255 | EXEC SQL END DECLARE SECTION; |
256 | int status; | |
257 | ||
258 | listname = argv[0]; | |
259 | EXEC SQL SELECT hidden, acl_id, acl_type INTO :flags, :acl_id, :acl_type | |
260 | FROM list WHERE name = :listname; | |
261 | ||
262 | rowcount = sqlca.sqlerrd[2]; | |
263 | if (rowcount > 1) | |
264 | return MR_WILDCARD; | |
265 | if (rowcount == 0) | |
266 | return MR_NO_MATCH; | |
267 | if (!flags) | |
268 | return MR_SUCCESS; | |
269 | ||
270 | /* check for client in access control list */ | |
271 | status = find_member(acl_type, acl_id, cl); | |
272 | if (!status) | |
273 | return MR_PERM; | |
274 | ||
275 | return MR_SUCCESS; | |
73cf66ba | 276 | } |
277 | ||
278 | ||
279 | /* access_member - allow user to access member of type "USER" and name matches | |
f3c08a60 | 280 | * username, or to access member of type "KERBEROS" and the principal matches |
281 | * the user, or to access member of type "LIST" and list is one that user is | |
73cf66ba | 282 | * on the acl of, or the list is visible. |
283 | */ | |
284 | ||
5eaef520 | 285 | int access_member(struct query *q, char *argv[], client *cl) |
73cf66ba | 286 | { |
5eaef520 | 287 | if (!strcmp(argv[0], "LIST") || !strcmp(argv[0], "RLIST")) |
288 | return access_visible_list(q, &argv[1], cl); | |
73cf66ba | 289 | |
5eaef520 | 290 | if (!strcmp(argv[0], "USER") || !strcmp(argv[0], "RUSER")) |
291 | { | |
292 | if (cl->users_id == *(int *)argv[1]) | |
293 | return MR_SUCCESS; | |
73cf66ba | 294 | } |
295 | ||
5eaef520 | 296 | if (!strcmp(argv[0], "KERBEROS") || !strcmp(argv[0], "RKERBEROS")) |
297 | { | |
298 | if (cl->client_id == -*(int *)argv[1]) | |
299 | return MR_SUCCESS; | |
73cf66ba | 300 | } |
301 | ||
5eaef520 | 302 | return MR_PERM; |
73cf66ba | 303 | } |
304 | ||
305 | ||
306 | /* access_qgli - special access routine for Qualified_get_lists. Allows | |
307 | * access iff argv[0] == "TRUE" and argv[2] == "FALSE". | |
308 | */ | |
309 | ||
5eaef520 | 310 | int access_qgli(struct query *q, char *argv[], client *cl) |
73cf66ba | 311 | { |
5eaef520 | 312 | if (!strcmp(argv[0], "TRUE") && !strcmp(argv[2], "FALSE")) |
313 | return MR_SUCCESS; | |
314 | return MR_PERM; | |
73cf66ba | 315 | } |
316 | ||
317 | ||
318 | /* access_service - allow access if user is on ACL of service. Don't | |
319 | * allow access if a wildcard is used. | |
320 | */ | |
321 | ||
5eaef520 | 322 | int access_service(struct query *q, char *argv[], client *cl) |
73cf66ba | 323 | { |
5eaef520 | 324 | EXEC SQL BEGIN DECLARE SECTION; |
325 | int acl_id; | |
e688520a | 326 | char *name, acl_type[LIST_ACL_TYPE_SIZE]; |
5eaef520 | 327 | EXEC SQL END DECLARE SECTION; |
328 | int status; | |
329 | char *c; | |
330 | ||
331 | name = argv[0]; | |
332 | for (c = name; *c; c++) | |
333 | { | |
334 | if (islower(*c)) | |
335 | *c = toupper(*c); | |
336 | } | |
337 | EXEC SQL SELECT acl_id, acl_type INTO :acl_id, :acl_type FROM servers | |
338 | WHERE name = :name; | |
339 | if (sqlca.sqlerrd[2] > 1) | |
340 | return MR_PERM; | |
341 | ||
342 | /* check for client in access control list */ | |
343 | status = find_member(acl_type, acl_id, cl); | |
344 | if (!status) | |
345 | return MR_PERM; | |
346 | ||
347 | return MR_SUCCESS; | |
73cf66ba | 348 | } |
349 | ||
350 | ||
351 | /* access_filesys - verify that client is owner or on owners list of filesystem | |
352 | * named by argv[0] | |
353 | */ | |
354 | ||
5eaef520 | 355 | int access_filesys(struct query *q, char *argv[], client *cl) |
73cf66ba | 356 | { |
5eaef520 | 357 | EXEC SQL BEGIN DECLARE SECTION; |
358 | int users_id, list_id; | |
359 | char *name; | |
360 | EXEC SQL END DECLARE SECTION; | |
361 | int status; | |
362 | ||
363 | name = argv[0]; | |
364 | EXEC SQL SELECT owner, owners INTO :users_id, :list_id FROM filesys | |
365 | WHERE label = :name; | |
366 | ||
367 | if (sqlca.sqlerrd[2] != 1) | |
368 | return MR_PERM; | |
369 | if (users_id == cl->users_id) | |
370 | return MR_SUCCESS; | |
371 | status = find_member("LIST", list_id, cl); | |
372 | if (status) | |
373 | return MR_SUCCESS; | |
374 | else | |
375 | return MR_PERM; | |
73cf66ba | 376 | } |
377 | ||
1beb5e23 | 378 | |
379 | /* access_host - successful if owner of host, or subnet containing host | |
380 | */ | |
381 | ||
5eaef520 | 382 | int access_host(struct query *q, char *argv[], client *cl) |
1beb5e23 | 383 | { |
5eaef520 | 384 | EXEC SQL BEGIN DECLARE SECTION; |
385 | int mid, sid, id; | |
e688520a | 386 | char mtype[MACHINE_OWNER_TYPE_SIZE], stype[SUBNET_OWNER_TYPE_SIZE]; |
5eaef520 | 387 | EXEC SQL END DECLARE SECTION; |
388 | int status; | |
389 | ||
17f090e1 | 390 | if (q->type == RETRIEVE) |
391 | { | |
392 | if (strcmp(argv[0], "*") || strcmp(argv[1], "*") || | |
393 | strcmp(argv[2], "*") || strcmp(argv[3], "*")) | |
394 | return MR_SUCCESS; | |
395 | else | |
396 | return MR_PERM; | |
397 | } | |
9e252e6f | 398 | |
5eaef520 | 399 | if (q->type == APPEND) |
400 | { | |
17f090e1 | 401 | /* Non-query owner must set use to zero */ |
402 | if (atoi(argv[6]) != 0) | |
403 | return MR_PERM; | |
404 | ||
9e252e6f | 405 | /* ... and start the hostname with a letter */ |
406 | if (isdigit(argv[0][0])) | |
407 | return MR_BAD_CHAR; | |
408 | ||
5eaef520 | 409 | id = *(int *)argv[8]; |
410 | EXEC SQL SELECT s.owner_type, s.owner_id | |
411 | INTO :stype, :sid FROM subnet s | |
412 | WHERE s.snet_id = :id; | |
413 | mid = 0; | |
17f090e1 | 414 | |
415 | if (find_member(stype, sid, cl)) | |
5eaef520 | 416 | return MR_SUCCESS; |
417 | else | |
418 | return MR_PERM; | |
419 | } | |
17f090e1 | 420 | else /* q-type == UPDATE */ |
5eaef520 | 421 | { |
17f090e1 | 422 | EXEC SQL BEGIN DECLARE SECTION; |
423 | int status, acomment, use, ocomment, snid; | |
e688520a | 424 | char contact[MACHINE_CONTACT_SIZE], address[MACHINE_ADDRESS_SIZE]; |
9e252e6f | 425 | char name[MACHINE_NAME_SIZE]; |
17f090e1 | 426 | EXEC SQL END DECLARE SECTION; |
427 | ||
5eaef520 | 428 | id = *(int *)argv[0]; |
9e252e6f | 429 | EXEC SQL SELECT m.name, m.use, m.contact, m.status, m.address, |
430 | m.owner_type, m.owner_id, m.acomment, m.ocomment, m.snet_id, | |
431 | s.owner_type, s.owner_id INTO :name, :use, :contact, :status, | |
432 | :address, :mtype, :mid, :acomment, :ocomment, :snid, :stype, :sid | |
17f090e1 | 433 | FROM machine m, subnet s |
434 | WHERE m.mach_id = :id AND s.snet_id = m.snet_id; | |
435 | if (dbms_errno) | |
436 | return mr_errcode; | |
437 | ||
438 | /* non-query-owner cannot change use or ocomment */ | |
439 | if ((use != atoi(argv[7])) || (ocomment != *(int *)argv[14])) | |
440 | return MR_PERM; | |
441 | ||
9e252e6f | 442 | /* or rename to start with digit */ |
443 | if (isdigit(argv[1][0]) && strcmp(strtrim(name), argv[1])) | |
444 | return MR_BAD_CHAR; | |
445 | ||
17f090e1 | 446 | if (!find_member(stype, sid, cl)) |
447 | { | |
448 | if (find_member(mtype, mid, cl)) | |
449 | { | |
450 | /* host owner also cannot change contact, status, address, | |
451 | owner, or acomment */ | |
452 | if (strcmp(argv[6], strtrim(contact)) || | |
453 | (status != atoi(argv[8])) || | |
454 | strcmp(argv[10], strtrim(address)) || | |
455 | strcmp(argv[11], strtrim(mtype)) || | |
456 | (mid != *(int *)argv[12]) || (acomment != *(int *)argv[13])) | |
457 | return MR_PERM; | |
458 | } | |
459 | else | |
460 | return MR_PERM; | |
461 | } | |
462 | ||
463 | /* If moving to a new subnet, make sure user is on acl there */ | |
464 | id = *(int *)argv[9]; | |
465 | if (id != snid) | |
466 | { | |
467 | EXEC SQL SELECT owner_type, owner_id INTO :stype, :sid | |
468 | FROM subnet WHERE snet_id=:id; | |
469 | if (!find_member(stype, sid, cl)) | |
470 | return MR_PERM; | |
471 | } | |
5eaef520 | 472 | |
5eaef520 | 473 | return MR_SUCCESS; |
1beb5e23 | 474 | } |
1beb5e23 | 475 | } |
476 | ||
477 | ||
478 | /* access_ahal - check for adding a host alias. | |
479 | * successful if host has less then 2 aliases and (client is owner of | |
480 | * host or subnet). | |
481 | * If deleting an alias, any owner will do. | |
482 | */ | |
483 | ||
5eaef520 | 484 | int access_ahal(struct query *q, char *argv[], client *cl) |
1beb5e23 | 485 | { |
5eaef520 | 486 | EXEC SQL BEGIN DECLARE SECTION; |
487 | int cnt, id, mid, sid; | |
e688520a | 488 | char mtype[MACHINE_OWNER_TYPE_SIZE], stype[SUBNET_OWNER_TYPE_SIZE]; |
5eaef520 | 489 | EXEC SQL END DECLARE SECTION; |
490 | int status; | |
491 | ||
492 | if (q->type == RETRIEVE) | |
493 | return MR_SUCCESS; | |
494 | ||
495 | id = *(int *)argv[1]; | |
496 | ||
9e252e6f | 497 | if (q->type == APPEND && isdigit(argv[0][0])) |
498 | return MR_BAD_CHAR; | |
499 | ||
5eaef520 | 500 | EXEC SQL SELECT count(name) INTO :cnt from hostalias WHERE mach_id = :id; |
501 | if (dbms_errno) | |
502 | return mr_errcode; | |
503 | /* if the type is APPEND, this is ahal and we need to make sure there | |
504 | * will be no more than 2 aliases. If it's not, it must be dhal and | |
505 | * any owner will do. | |
506 | */ | |
507 | if (q->type == APPEND && cnt >= 2) | |
508 | return MR_PERM; | |
509 | EXEC SQL SELECT m.owner_type, m.owner_id, s.owner_type, s.owner_id | |
510 | INTO :mtype, :mid, :stype, :sid FROM machine m, subnet s | |
511 | WHERE m.mach_id = :id and s.snet_id = m.snet_id; | |
512 | status = find_member(mtype, mid, cl); | |
513 | if (status) | |
514 | return MR_SUCCESS; | |
515 | status = find_member(stype, sid, cl); | |
516 | if (status) | |
517 | return MR_SUCCESS; | |
518 | else | |
519 | return MR_PERM; | |
1beb5e23 | 520 | } |
7cf83f0f | 521 | |
522 | ||
7cf83f0f | 523 | /* access_snt - check for retrieving network structure |
524 | */ | |
525 | ||
5eaef520 | 526 | int access_snt(struct query *q, char *argv[], client *cl) |
7cf83f0f | 527 | { |
5eaef520 | 528 | if (q->type == RETRIEVE) |
529 | return MR_SUCCESS; | |
7cf83f0f | 530 | |
5eaef520 | 531 | return MR_PERM; |
7cf83f0f | 532 | } |
1a9a0a59 | 533 | |
534 | ||
535 | /* access_printer */ | |
536 | int access_printer(struct query *q, char *argv[], client *cl) | |
537 | { | |
538 | EXEC SQL BEGIN DECLARE SECTION; | |
539 | char type[PRINTSERVERS_OWNER_TYPE_SIZE]; | |
540 | int id, mach_id; | |
541 | EXEC SQL END DECLARE SECTION; | |
542 | int status; | |
543 | ||
544 | mach_id = *(int *)argv[PRN_RM]; | |
545 | EXEC SQL SELECT owner_type, owner_id INTO :type, :id | |
546 | FROM printservers WHERE mach_id = :mach_id; | |
547 | if (sqlca.sqlcode) | |
548 | return MR_PERM; | |
549 | ||
550 | status = find_member(type, id, cl); | |
551 | if (status) | |
552 | return MR_SUCCESS; | |
553 | else | |
554 | return MR_PERM; | |
555 | } |