-
Notifications
You must be signed in to change notification settings - Fork 0
/
munge.go
201 lines (164 loc) · 4.97 KB
/
munge.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
// Copyright 2024 Andrew E. Bruno. All rights reserved.
//
// This file is part of gomunge.
//
// gomunge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// gomunge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with gomunge. If not, see <https://www.gnu.org/licenses/>.
// Package munge is a cgo wrapper for MUNGE
package munge
/*
#cgo CFLAGS: -std=gnu99
#cgo LDFLAGS: -lmunge
#include "gmunge.h"
*/
import "C"
import (
"errors"
"fmt"
)
var (
// ErrCredInvalid is returned when a credential is invalid
ErrCredInvalid = errors.New("Invalid credential")
// ErrCredExpired is returned when a credential is expired
ErrCredExpired = errors.New("Expired credential")
// ErrCredRewound is returned when a credential is rewound
ErrCredRewound = errors.New("Rewound credential")
// ErrCredReplayed is returned when a credential is replayed
ErrCredReplayed = errors.New("Replayed credential")
// ErrCredUnauthorized is returned when an unauthorized credential decode is performed
ErrCredUnauthorized = errors.New("Unauthorized credential decode")
)
// Option for configuring munge credential
type Option func(*Credential)
// Credential is the munge credential
type Credential struct {
uid uint32
gid uint32
payload []byte
ttl int
}
// NewCredential creates a new munge credential with default options.
func NewCredential(options ...Option) *Credential {
credential := &Credential{}
for _, opt := range options {
opt(credential)
}
return credential
}
// WithPayload sets the payload for the munge credential.
func WithPayload(payload []byte) Option {
return func(m *Credential) {
m.payload = payload
}
}
// WithTTL sets the time-to-live for the munge credential.
func WithTTL(ttl int) Option {
return func(m *Credential) {
m.ttl = ttl
}
}
// Encode returns base64 encoded munge Credential
func (m *Credential) Encode() (string, error) {
var conf C.conf_t
conf = C.create_conf()
if m.payload != nil && len(m.payload) > 0 {
conf.data = C.CBytes(m.payload)
conf.dlen = C.int(len(m.payload))
}
if m.ttl != 0 {
if m.ttl < -1 {
return "", fmt.Errorf("Invalid time-to-live: %d", m.ttl)
}
var ret C.int
if m.ttl == -1 {
ret = C.set_opt_int(conf.ctx, C.MUNGE_OPT_TTL, C.MUNGE_TTL_MAXIMUM)
} else {
ret = C.set_opt_int(conf.ctx, C.MUNGE_OPT_TTL, C.int(m.ttl))
}
if ret != C.EMUNGE_SUCCESS {
return "", fmt.Errorf("Failed to set ttl: %d", ret)
}
}
ret := C.encode_cred(conf)
if ret != C.EMUNGE_SUCCESS {
return "", fmt.Errorf("Failed to encode: %d", ret)
}
cred := C.GoString(conf.cred)
C.destroy_conf(conf)
return cred, nil
}
// TTL returns the time-to-live of the credential
func (m *Credential) TTL() int {
return m.ttl
}
// Uid returns the uid of the client that requested the credential
func (m *Credential) Uid() uint32 {
return m.uid
}
// Uid returns the uid as a string of the client that requested the credential
func (m *Credential) UidString() string {
return fmt.Sprintf("%d", m.uid)
}
// Gid returns the gid of the client that requested the credential
func (m *Credential) Gid() uint32 {
return m.gid
}
// Gid returns the gid as a string of the client that requested the credential
func (m *Credential) GidString() string {
return fmt.Sprintf("%d", m.gid)
}
// Payload returns the payload data munged into the credential
func (m *Credential) Payload() []byte {
return m.payload
}
// Encode returns base64 encoded munge Credential with default options
func Encode() (string, error) {
cred := NewCredential()
return cred.Encode()
}
// Decode base64 cred into a munge Credential
func Decode(cred string) (*Credential, error) {
var conf C.conf_t
conf = C.create_conf()
conf.cred = C.CString(cred)
ret := C.decode_cred(conf)
if ret != C.EMUNGE_SUCCESS {
switch ret {
case C.EMUNGE_CRED_INVALID:
return nil, ErrCredInvalid
case C.EMUNGE_CRED_EXPIRED:
return nil, ErrCredExpired
case C.EMUNGE_CRED_REWOUND:
return nil, ErrCredRewound
case C.EMUNGE_CRED_REPLAYED:
return nil, ErrCredReplayed
case C.EMUNGE_CRED_UNAUTHORIZED:
return nil, ErrCredUnauthorized
default:
msg := C.GoString(C.munge_strerror(conf.status))
return nil, fmt.Errorf("Failed to decode: %s", msg)
}
}
credential := &Credential{}
credential.uid = uint32(conf.cuid)
credential.gid = uint32(conf.cgid)
credential.payload = C.GoBytes(conf.data, conf.dlen)
var ttl C.int
ret = C.get_opt_int(conf.ctx, C.MUNGE_OPT_TTL, &ttl)
if ret != C.EMUNGE_SUCCESS {
return nil, fmt.Errorf("Failed to get ttl from context: %d", ret)
}
credential.ttl = int(ttl)
C.destroy_conf(conf)
return credential, nil
}