1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
13: class Beatnik {
14:
15: 16: 17:
18: function ($returnType = 'object')
19: {
20:
21: $editing = Horde_Util::getFormData('id');
22: $editing = !empty($editing);
23:
24: $menu = new Horde_Menu();
25:
26: $menu->add(Horde::url('listzones.php'), _('List Domains'), 'website.png');
27: if (!empty($_SESSION['beatnik']['curdomain'])) {
28: $menu->add(Horde_Util::addParameter(Horde::url('editrec.php'), 'curdomain', $_SESSION['beatnik']['curdomain']['zonename']), ($editing) ? _("Edit Record") : _("Add Record"), 'edit.png');
29: } else {
30: $menu->add(Horde::url('editrec.php?rectype=soa'), _("Add Zone"), 'edit.png');
31: }
32:
33: $url = Horde_Util::addParameter(Horde::selfUrl(true), array('expertmode' => 'toggle'));
34: $menu->add($url, _('Expert Mode'), 'hide_panel.png', null, '', null, ($_SESSION['beatnik']['expertmode']) ? 'current' : '');
35:
36: if (count(Beatnik::needCommit())) {
37: $url = Horde_Util::addParameter(Horde::url('commit.php'), array('domain' => 'all'));
38: $menu->add($url, _('Commit All'), 'commit-all.png');
39: }
40:
41: if ($returnType == 'object') {
42: return $menu;
43: } else {
44: return $menu->render();
45: }
46: }
47:
48: 49: 50: 51: 52: 53:
54: function getRecTypes()
55: {
56: $beatnik = $GLOBALS['registry']->getApiInstance('beatnik', 'application');
57:
58: $records = array(
59: 'soa' => _("SOA (Start of Authority)"),
60: 'ns' => _("NS (Name Server)"),
61: 'a' => _("A (Address)"),
62: 'aaaa' => _("AAAA (IPv6 Address)"),
63: 'ptr' => _("PTR (Reverse DNS)"),
64: 'cname' => _("CNAME (Alias)"),
65: 'mx' => _("MX (Mail eXchange)"),
66: 'srv' => _("SRV (Service Record)"),
67: 'txt' => _("TXT (Text Record)"),
68: );
69:
70: return array_merge($records, $beatnik->driver->getRecDriverTypes());
71: }
72:
73: 74:
75: function getRecFields($recordtype)
76: {
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92: $beatnik = $GLOBALS['registry']->getApiInstance('beatnik', 'application');
93:
94:
95: static $recset = array();
96:
97: if (isset($recset[$recordtype])) {
98: return $recset[$recordtype];
99: }
100: $recset[$recordtype] = array();
101:
102: $recset[$recordtype]['id'] = array(
103: 'name' => _("UID"),
104: 'description' => _("Unique Identifier (Used as Record ID)"),
105: 'type' => 'hidden',
106: 'maxlength' => 0,
107: 'required' => false,
108: 'infoset' => 'basic',
109: 'index' => 0,
110: );
111:
112: switch (strtolower($recordtype)) {
113: case 'soa':
114: $recset[$recordtype]['zonename'] = array(
115: 'name' => _("Domain Name"),
116: 'description' => _("Zone Domain Name"),
117: 'type' => 'text',
118: 'maxlength' => 0,
119: 'required' => true,
120: 'infoset' => 'basic',
121: 'index' => 1,
122: );
123: $recset[$recordtype]['zonens'] = array(
124: 'name' => _("Primary Nameserver"),
125: 'description' => _("Primary nameserver for this zone"),
126: 'type' => 'text',
127: 'maxlength' => 0,
128: 'required' => true,
129: 'infoset' => 'basic',
130: 'index' => 2,
131: );
132: $recset[$recordtype]['zonecontact'] = array(
133: 'name' => _("Zone Contact"),
134: 'description' => _("Contact e-mail address for this zone"),
135: 'type' => 'text',
136: 'maxlength' => 0,
137: 'required' => true,
138: 'infoset' => 'basic',
139: 'index' => 2,
140: );
141: $recset[$recordtype]['serial'] = array(
142: 'name' => _("Serial"),
143: 'description' => _("Zone Serial Number"),
144: 'type' => 'int',
145: 'default' => date('Ymd'). '00',
146: 'maxlength' => 0,
147: 'required' => false,
148: 'infoset' => 'advanced',
149: 'index' => 3,
150: );
151: $recset[$recordtype]['refresh'] = array(
152: 'name' => 'Refresh',
153: 'description' => _("Zone Refresh"),
154: 'type' => 'int',
155: 'maxlength' => 0,
156: 'required' => false,
157: 'infoset' => 'advanced',
158: 'index' => 4,
159: );
160: $recset[$recordtype]['retry'] = array(
161: 'name' => _("Retry"),
162: 'description' => _("Zone Retry"),
163: 'type' => 'int',
164: 'maxlength' => 0,
165: 'required' => false,
166: 'infoset' => 'advanced',
167: 'index' => 5,
168: );
169: $recset[$recordtype]['expire'] = array(
170: 'name' => _("Expiration"),
171: 'description' => _("Zone Expiry"),
172: 'type' => 'int',
173: 'maxlength' => 0,
174: 'required' => false,
175: 'infoset' => 'advanced',
176: 'index' => 6,
177: );
178: $recset[$recordtype]['minimum'] = array(
179: 'name' => _("Minimum"),
180: 'description' => _("Zone Minimum"),
181: 'type' => 'int',
182: 'maxlength' => 0,
183: 'required' => false,
184: 'infoset' => 'advanced',
185: 'index' => 7,
186: );
187: break;
188:
189: case 'a':
190: $recset[$recordtype]['hostname'] = array(
191: 'name' => _("Hostname"),
192: 'description' => _("Short hostname for this record"),
193: 'type' => 'text',
194: 'maxlength' => 0,
195: 'required' => true,
196: 'infoset' => 'basic',
197: 'index' => 1,
198: );
199: $recset[$recordtype]['ipaddr'] = array(
200: 'name' => _("IP Address"),
201: 'description' => _("IPv4 Network Address"),
202: 'type' => 'ipaddress',
203: 'maxlength' => 0,
204: 'required' => true,
205: 'infoset' => 'basic',
206: 'index' => 2,
207: );
208: break;
209:
210: case 'aaaa':
211: $recset[$recordtype]['hostname'] = array(
212: 'name' => _("Hostname"),
213: 'description' => _("Short hostname for this record"),
214: 'type' => 'text',
215: 'maxlength' => 0,
216: 'required' => true,
217: 'infoset' => 'basic',
218: 'index' => 1,
219: );
220: $recset[$recordtype]['ip6addr'] = array(
221: 'name' => _("IPv6 Address"),
222: 'description' => _("IPv6 Network Address"),
223: 'type' => 'ip6address',
224: 'maxlength' => 0,
225: 'required' => true,
226: 'infoset' => 'basic',
227: 'index' => 2,
228: );
229: break;
230:
231: case 'ptr':
232: $recset[$recordtype]['hostname'] = array(
233: 'name' => _("Hostname"),
234: 'description' => _("IP in Reverse notation (.in-addr.arpa)"),
235: 'type' => 'text',
236: 'maxlength' => 0,
237: 'required' => true,
238: 'infoset' => 'basic',
239: 'index' => 1,
240: );
241: $recset[$recordtype]['pointer'] = array(
242: 'name' => _("Hostname Target"),
243: 'description' => _("Hostname for Reverse DNS"),
244: 'type' => 'text',
245: 'maxlength' => 0,
246: 'required' => true,
247: 'infoset' => 'basic',
248: 'index' => 2,
249: );
250: break;
251:
252: case 'mx':
253: $recset[$recordtype]['pointer'] = array(
254: 'name' => _("Hostname Target"),
255: 'description' => _("Hostname of Mail eXchanger"),
256: 'type' => 'text',
257: 'maxlength' => 0,
258: 'required' => true,
259: 'infoset' => 'basic',
260: 'index' => 1,
261: );
262: $recset[$recordtype]['pref'] = array(
263: 'name' => _("Preference"),
264: 'description' => _("MX Preference (lower is more preferred)"),
265: 'type' => 'int',
266: 'default' => 0,
267: 'maxlength' => 0,
268: 'required' => true,
269: 'infoset' => 'basic',
270: 'index' => 2,
271: );
272: break;
273:
274: case 'cname':
275: $recset[$recordtype]['hostname'] = array(
276: 'name' => _("Hostname"),
277: 'description' => _("Short hostname for this record"),
278: 'type' => 'text',
279: 'maxlength' => 0,
280: 'required' => true,
281: 'infoset' => 'basic',
282: 'index' => 1,
283: );
284: $recset[$recordtype]['pointer'] = array(
285: 'name' => _("Hostname Target"),
286: 'description' => _("Hostname for CNAME alias"),
287: 'type' => 'text',
288: 'maxlength' => 0,
289: 'required' => true,
290: 'infoset' => 'basic',
291: 'index' => 2,
292: );
293: break;
294:
295: case 'ns':
296: $recset[$recordtype]['hostname'] = array(
297: 'name' => _("Domain Name"),
298: 'description' => _("Short sub-domain for NS record (leave blank unless creating a subdomain)"),
299: 'type' => 'text',
300: 'maxlength' => 0,
301: 'required' => false,
302:
303: 'default' => @$GLOBALS['curdomain']['zonename'],
304: 'infoset' => 'basic',
305: 'index' => 1,
306: );
307: $recset[$recordtype]['pointer'] = array(
308: 'name' => _("Hostname Target"),
309: 'description' => _("Hostname of Authoritative Name Server"),
310: 'type' => 'text',
311: 'maxlength' => 0,
312: 'required' => true,
313: 'infoset' => 'basic',
314: 'index' => 2,
315: );
316: break;
317:
318: case 'srv':
319: $recset[$recordtype]['hostname'] = array(
320: 'name' => _("Hostname"),
321: 'description' => _("Short hostname for this record"),
322: 'type' => 'text',
323: 'maxlength' => 0,
324: 'required' => true,
325: 'infoset' => 'basic',
326: 'index' => 1,
327: );
328: $recset[$recordtype]['pointer'] = array(
329: 'name' => _("Hostname Target"),
330: 'description' => _("Hostname for DNS Service Record"),
331: 'type' => 'text',
332: 'maxlength' => 0,
333: 'required' => true,
334: 'infoset' => 'basic',
335: 'index' => 2,
336: );
337: $recset[$recordtype]['priority'] = array(
338: 'name' => _("SRV Priority"),
339: 'description' => _("DNS Service Record Priority"),
340: 'type' => 'int',
341: 'default' => 0,
342: 'maxlength' => 0,
343: 'required' => true,
344: 'infoset' => 'basic',
345: 'index' => 3,
346: );
347: $recset[$recordtype]['weight'] = array(
348: 'name' => _("SRV Weight"),
349: 'description' => _("DNS Service Record Weight"),
350: 'type' => 'int',
351: 'default' => 0,
352: 'maxlength' => 0,
353: 'required' => true,
354: 'infoset' => 'basic',
355: 'index' => 4,
356: );
357: $recset[$recordtype]['port'] = array(
358: 'name' => _("SRV Port"),
359: 'description' => _("DNS Service Record Port Number"),
360: 'type' => 'int',
361: 'default' => 0,
362: 'maxlength' => 0,
363: 'required' => true,
364: 'infoset' => 'basic',
365: 'index' => 5,
366: );
367: break;
368:
369: case 'txt':
370: $recset[$recordtype]['hostname'] = array(
371: 'name' => _("Hostname"),
372: 'description' => _("Short hostname for this record"),
373: 'type' => 'text',
374: 'maxlength' => 0,
375: 'required' => true,
376: 'infoset' => 'basic',
377: 'index' => 1,
378: );
379: $recset[$recordtype]['text'] = array(
380: 'name' => 'Text',
381: 'description' => _("String payload for DNS TXT"),
382: 'type' => 'text',
383: 'maxlength' => 256,
384: 'required' => true,
385: 'infoset' => 'basic',
386: 'index' => 2,
387: );
388: break;
389: }
390:
391: $recset[$recordtype]['ttl'] = array(
392: 'name' => _("TTL"),
393: 'description' => _("Record Time-To-Live (seconds)"),
394: 'type' => 'int',
395: 'maxlength' => 0,
396: 'required' => false,
397: 'infoset' => 'advanced',
398: 'index' => 100,
399: 'default' => $GLOBALS['prefs']->getValue('default_ttl')
400: );
401:
402:
403: uasort($recset[$recordtype], array('Beatnik', 'fieldSort'));
404:
405: return $recset[$recordtype];
406: }
407:
408: 409: 410: 411: 412: 413: 414: 415: 416: 417: 418: 419: 420: 421: 422: 423: 424:
425: function needCommit($domain = null, $needcommit = null)
426: {
427:
428: if (!isset($_SESSION['beatnik']['needcommit'])) {
429: $_SESSION['beatnik']['needcommit'] = array();
430: }
431:
432: if ($domain === null && $needcommit === null) {
433:
434: return array_keys($_SESSION['beatnik']['needcommit']);
435: } elseif ($domain !== null && $needcommit === null) {
436:
437: return isset($_SESSION['beatnik']['needcommit'][$domain]);
438: } elseif ($domain !== null && is_bool($needcommit)) {
439:
440: if ($needcommit) {
441: if(!isset($_SESSION['beatnik']['needcommit'][$domain])) {
442: $_SESSION['beatnik']['needcommit'][$domain] = true;
443: }
444: } else {
445: if (isset($_SESSION['beatnik']['needcommit'][$domain])) {
446: unset($_SESSION['beatnik']['needcommit'][$domain]);
447: }
448: }
449: return true;
450: } else {
451:
452: throw new Beatnik_Exception(_("Unable to determine if domain needs committing: invalid parameter."));
453: }
454: }
455:
456: function notifyCommits()
457: {
458:
459:
460: if (count(Beatnik::needCommit())) {
461: foreach (Beatnik::needCommit() as $domain) {
462: $GLOBALS['notification']->push(sprintf(_("You have uncommitted changes in %s."), $domain));
463: }
464: }
465: }
466:
467: 468: 469: 470: 471: 472: 473: 474: 475: 476: 477: 478: 479: 480:
481: function hasPermission($permname, $permmask = null, $numparents = 0)
482: {
483: if ($GLOBALS['registry']->isAdmin()) {
484: return true;
485: }
486:
487: if ($permmask === null) {
488: $permmask = Horde_Perms::SHOW | Horde_Perms::READ;
489: }
490:
491:
492: $user = 0;
493: $superadmin = 0;
494:
495: $superadmin = $GLOBALS['injector']->getInstance('Horde_Perms')->hasPermission('beatnik:domains', $GLOBALS['registry']->getAuth(), $permmask);
496:
497: while ($numparents >= 0) {
498: $tmpuser = $GLOBALS['injector']->getInstance('Horde_Perms')->hasPermission($permname, $GLOBALS['registry']->getAuth(), $permmask);
499:
500: $user = $user | $tmpuser;
501: if ($numparents > 0) {
502: $pos = strrpos($permname, ':');
503: if ($pos) {
504: $permname = substr($permname, 0, $pos);
505: }
506: }
507: $numparents--;
508: }
509: return (($superadmin | $user) & $permmask);
510: }
511:
512: 513: 514: 515: 516: 517: 518: 519:
520: function autogenerate(&$vars)
521: {
522: $beatnik = $GLOBALS['registry']->getApiInstance('beatnik', 'application');
523:
524: require BEATNIK_BASE . '/config/autogenerate.php';
525: $template = $templates[$vars->get('template')];
526: try {
527: $zonedata = $beatnik->driver->getRecords($_SESSION['beatnik']['curdomain']['zonename']);
528: } catch (Exception $e) {
529: $GLOBALS['notification']->push($e);
530: }
531:
532: foreach ($template['types'] as $rectype => $definitions) {
533:
534: if (isset($zonedata[$rectype])) {
535:
536: switch($definitions['replace']) {
537: case 'all':
538: foreach ($zonedata[$rectype] as $record) {
539: try {
540: $result = $beatnik->driver->deleteRecord($record);
541: } catch (Exception $e) {
542: $GLOBALS['notification']->push($e);
543: }
544: }
545: break;
546:
547: case 'match':
548: foreach ($zonedata[$rectype] as $record) {
549:
550:
551: foreach ($definitions['records'] as $Trecord) {
552: if ($record['hostname'] == $Trecord['hostname']) {
553: try {
554: $result = $beatnik->driver->deleteRecord($record);
555: } catch (Exception $e) {
556: $GLOBALS['notification']->push($e);
557: }
558: }
559: }
560: }
561: break;
562:
563:
564:
565: }
566: }
567:
568: $defaults = array('rectype' => $rectype,
569: 'zonename'=> $_SESSION['beatnik']['curdomain']['zonename']);
570: foreach ($definitions['records'] as $info) {
571: if ($beatnik->driver->recordExists($info, $rectype)) {
572: $GLOBALS['notification']->push(_("Skipping existing identical record"));
573: continue;
574: }
575: try {
576: $result = $beatnik->driver->saveRecord(array_merge($defaults, $info));
577: $GLOBALS['notification']->push(sprintf(_('Record added: %s/%s'), $rectype, $info['hostname']), 'horde.success');
578: } catch (Exception $e) {
579: $GLOBALS['notification']->push($e->getMessage(), 'horde.error');
580: return false;
581: }
582: }
583: }
584: return true;
585: }
586:
587: 588: 589: 590: 591: 592: 593:
594: function incrementSerial($serial)
595: {
596:
597:
598:
599:
600: $newserial = (int) (date('Ymd') . '00');
601: if ($serial < $newserial) {
602: return $newserial;
603: } else {
604: return ++$serial;
605: }
606: }
607:
608: 609: 610: 611: 612: 613: 614: 615:
616: function fieldSort($a, $b)
617: {
618: if ($a['index'] < $b['index']) {
619: return -1;
620: } elseif ($a['index'] > $b['index']) {
621: return 1;
622: } else {
623: return 0;
624: }
625: }
626:
627: }
628: