summaryrefslogtreecommitdiff
path: root/nslcd_proto/nslcd_h.go
blob: cb210cdbb53995b132649439c42685a0527b1abc (plain)
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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
// This file is based heavily on nslcd.h from nss-pam-ldapd
// Copyright (C) 2015 Luke Shumaker
/*
   nslcd.h - file describing client/server protocol

   Copyright (C) 2006 West Consulting
   Copyright (C) 2006, 2007, 2009, 2010, 2011, 2012, 2013 Arthur de Jong

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   This library 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
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
   02110-1301 USA
*/

package nslcd_proto

import (
	"fmt"
	"io"
	"net"
)

/*
   The protocol used between the nslcd client and server is a simple binary
   protocol. It is request/response based where the client initiates a
   connection, does a single request and closes the connection again. Any
   mangled or not understood messages will be silently ignored by the server.

   A request looks like:
     INT32  NSLCD_VERSION
     INT32  NSLCD_ACTION_*
     [request parameters if any]
   A response looks like:
     INT32  NSLCD_VERSION
     INT32  NSLCD_ACTION_* (the original request type)
     [result(s)]
     INT32  NSLCD_RESULT_END
   A single result entry looks like:
     NSLCD_RESULT_BEGIN int32
     [result value(s)]
   If a response would return multiple values (e.g. for NSLCD_ACTION_*_ALL
   functions) each return value will be preceded by a NSLCD_RESULT_BEGIN
   value. After the last returned result the server sends
   NSLCD_RESULT_END. If some error occurs (e.g. LDAP server unavailable,
   error in the request, etc) the server terminates the connection to signal
   an error condition (breaking the protocol).

   These are the available basic data types:
     INT32  - 32-bit integer value
     TYPE   - a typed field that is transferred using sizeof()
     STRING - a string length (32bit) followed by the string value (not
              null-terminted) the string itself is assumed to be UTF-8
     STRINGLIST - a 32-bit number noting the number of strings followed by
                  the strings one at a time

   Furthermore the ADDRESS compound data type is defined as:
     INT32  type of address: e.g. AF_INET or AF_INET6
     INT32  lenght of address
     RAW    the address itself
   With the ADDRESSLIST using the same construct as with STRINGLIST.

   The protocol uses network byte order for all types.
*/
// These basic data types are implemented in `io.go`

/* The current version of the protocol. This protocol should only be
   updated with major backwards-incompatible changes. */
const NSLCD_VERSION int32 = 0x00000002

/* Get a NSLCD configuration option. There is one request parameter: */
type Request_Config_Get struct {
	Key int32 /* NSLCD_CONFIG_* */
}
/* the result value is: */
type Config struct {
	Value string /* interpretation depending on request */
}
const NSLCD_ACTION_CONFIG_GET        int32 = 0x00010001

const (
	/* return the message, if any, that is presented to the user when password
	   modification through PAM is prohibited */
	NSLCD_CONFIG_PAM_PASSWORD_PROHIBIT_MESSAGE int32 = 1
)

/* Email alias (/etc/aliases) NSS requests. The result values for a
   single entry are: */
type Alias struct {
	Name       string
	Recipients []string
}
const NSLCD_ACTION_ALIAS_BYNAME      int32 = 0x00020001; type Request_Alias_ByName struct { Name string }
const NSLCD_ACTION_ALIAS_ALL         int32 = 0x00020008; type Request_Alias_All    struct {}

/* Ethernet address/name mapping NSS requests. The result values for a
   single entry are: */
type Ether struct {
	Name    string
	Address [6]byte
}
const NSLCD_ACTION_ETHER_BYNAME      int32 = 0x00030001; type Request_Ether_ByName  struct { Name string }
const NSLCD_ACTION_ETHER_BYETHER     int32 = 0x00030002; type Request_Ether_ByEther struct { Ether [6]byte }
const NSLCD_ACTION_ETHER_ALL         int32 = 0x00030008; type Request_Ether_All     struct {}

/* Group and group membership related NSS requests. The result values
   for a single entry are: */
type Group struct {
	Name    string
	PwHash  string
	ID      int32
	Members []string
}
/*   (note that the BYMEMER call returns an emtpy members list) */
const NSLCD_ACTION_GROUP_BYNAME      int32 = 0x00040001; type Request_Group_ByName   struct { Name string }
const NSLCD_ACTION_GROUP_BYGID       int32 = 0x00040002; type Request_Group_ByGid    struct { Gid int32 }
const NSLCD_ACTION_GROUP_BYMEMBER    int32 = 0x00040006; type Request_Group_ByMember struct { Member string }
const NSLCD_ACTION_GROUP_ALL         int32 = 0x00040008; type Request_Group_All      struct {}

/* Hostname (/etc/hosts) lookup NSS requests. The result values
   for an entry are: */
type Host struct {
	Name      string
	Aliases   []string
	Addresses []net.IP
}
const NSLCD_ACTION_HOST_BYNAME       int32 = 0x00050001; type Request_Host_ByName struct { Name string }
const NSLCD_ACTION_HOST_BYADDR       int32 = 0x00050002; type Request_Host_ByAddr struct { Addr net.IP }
const NSLCD_ACTION_HOST_ALL          int32 = 0x00050008; type Request_Host_All    struct {}

/* Netgroup NSS result entries contain a number of parts. A result entry
   starts with:
     STRING  netgroup name
   followed by zero or more references to other netgroups or netgroup
   triples. A reference to another netgroup looks like:
     INT32   NSLCD_NETGROUP_TYPE_NETGROUP
     STRING  other netgroup name
   A a netgroup triple looks like:
     INT32   NSLCD_NETGROUP_TYPE_TRIPLE
     STRING  host
     STRING  user
     STRING  domain
   A netgroup result entry is terminated by:
     INT32   NSLCD_NETGROUP_TYPE_END
   */
type Netgroup_Netgroup struct {
	Name string
}
type Netgroup_Triple struct {
	Host   string
	User   string
	Domain string
}
type Netgroup_PartList []interface{}
func (data Netgroup_PartList) nslcdWrite(fd io.Writer) {
	for _, part := range data {
		var t int32 = -1
		switch part.(type) {
		case Netgroup_Netgroup:
			t = NSLCD_NETGROUP_TYPE_NETGROUP
		case Netgroup_Triple:
			t = NSLCD_NETGROUP_TYPE_TRIPLE
		}
		if t < 0 {
			panic("unrecognized netgroup type")
		}
		Write(fd, t)
		Write(fd, part)
	}
	Write(fd, NSLCD_NETGROUP_TYPE_END)
}
func (data *Netgroup_PartList) nslcdRead(fd io.Reader) {
	*data = make([]interface{}, 0)
	for {
		var t int32
		var v interface{}
		Read(fd, &t)
		switch t {
		case NSLCD_NETGROUP_TYPE_NETGROUP:
			v = Netgroup_Netgroup{}
		case NSLCD_NETGROUP_TYPE_TRIPLE:
			v = Netgroup_Triple{}
		case NSLCD_NETGROUP_TYPE_END:
			return
		default:
			panic(NslcdError(fmt.Sprintf("unrecognized netgroup type: %#08x", t)))
		}
		Read(fd, &v)
		*data = append(*data, v)
	}
}
var _ nslcdObject = Netgroup_PartList{}
var _ nslcdObjectPtr = &Netgroup_PartList{}
type Netgroup struct {
	Name  string
	Parts Netgroup_PartList
}
const NSLCD_ACTION_NETGROUP_BYNAME   int32 = 0x00060001; type Request_Netgroup_ByName struct { Name string }
const NSLCD_ACTION_NETGROUP_ALL      int32 = 0x00060008; type Request_Netgroup_All    struct {}
const (
	NSLCD_NETGROUP_TYPE_NETGROUP int32 = 1
	NSLCD_NETGROUP_TYPE_TRIPLE   int32 = 2
	NSLCD_NETGROUP_TYPE_END      int32 = 3
)

/* Network name (/etc/networks) NSS requests. Result values for a single
   entry are: */
type Network struct {
	Name      string
	Aliases   []string
	Addresses []net.IP
}
const NSLCD_ACTION_NETWORK_BYNAME    int32 = 0x00070001; type Request_Network_ByName struct { Name string }
const NSLCD_ACTION_NETWORK_BYADDR    int32 = 0x00070002; type Request_Network_ByAddr struct { Addr net.IP }
const NSLCD_ACTION_NETWORK_ALL       int32 = 0x00070008; type Request_Network_All    struct {}

/* User account (/etc/passwd) NSS requests. Result values are: */
type Passwd struct {
	Name    string
	PwHash  string
	UID     int32
	GID     int32
	GECOS   string
	HomeDir string
	Shell   string
}
const NSLCD_ACTION_PASSWD_BYNAME     int32 = 0x00080001; type Request_Passwd_ByName struct { Name string }
const NSLCD_ACTION_PASSWD_BYUID      int32 = 0x00080002; type Request_Passwd_ByUID  struct { UID int32 }
const NSLCD_ACTION_PASSWD_ALL        int32 = 0x00080008; type Request_Passwd_All    struct {}

/* Protocol information requests. Result values are: */
type Protocol struct {
	Name    string
	Aliases []string
	Number  int32
}
const NSLCD_ACTION_PROTOCOL_BYNAME   int32 = 0x00090001; type Request_Protocol_ByName   struct { Name string }
const NSLCD_ACTION_PROTOCOL_BYNUMBER int32 = 0x00090002; type Request_Protocol_ByNumber struct { Number int32 }
const NSLCD_ACTION_PROTOCOL_ALL      int32 = 0x00090008; type Request_Protocol_All      struct {}

/* RPC information requests. Result values are: */
type RPC struct {
	Name    string
	Aliases []string
	Number  int32
}
const NSLCD_ACTION_RPC_BYNAME        int32 = 0x000a0001; type Request_RPC_ByName   struct { Name string }
const NSLCD_ACTION_RPC_BYNUMBER      int32 = 0x000a0002; type Request_RPC_ByNumber struct { Number int32 }
const NSLCD_ACTION_RPC_ALL           int32 = 0x000a0008; type Request_RPC_All      struct {}

/* Service (/etc/services) information requests. The BYNAME and BYNUMBER
   requests contain an extra protocol string in the request which, if not
   blank, will filter the services by this protocol. Result values are: */
type Service struct {
	Name       string
	Aliases    []string
	PortNumber int32
	Protocol   string
}
const NSLCD_ACTION_SERVICE_BYNAME    int32 = 0x000b0001; type Request_Service_ByName   struct { Name string }
const NSLCD_ACTION_SERVICE_BYNUMBER  int32 = 0x000b0002; type Request_Service_ByNumber struct { Number int32 }
const NSLCD_ACTION_SERVICE_ALL       int32 = 0x000b0008; type Request_Service_All      struct {}

/* Extended user account (/etc/shadow) information requests. Result
   values for a single entry are: */
type Shadow struct {
	// It is my understanding that an empty value for an INT32
	// field is expressed with a negative number. -- lukeshu
	Name           string
	PwHash         string
	LastChangeDate int32
	MinDays        int32
	MaxDays        int32
	WarnDays       int32
	InactDays      int32
	ExpireDate     int32
	Flag           int32
}
const NSLCD_ACTION_SHADOW_BYNAME     int32 = 0x000c0001; type Request_Shadow_ByName struct { Name string }
const NSLCD_ACTION_SHADOW_ALL        int32 = 0x000c0008; type Request_Shadow_All    struct {}

/* PAM-related requests. The request parameters for all these requests
   begin with: */
type PAM_Base struct {
	UserName    string
	ServiceName string
	RUser       string
	RHost       string
	TTY         string
}
/* If the user is not known in LDAP no result may be returned (immediately
   return NSLCD_RESULT_END instead of a PAM error code). */

/* PAM authentication check request. The extra request values are: */
type Request_PAM_Authentication struct {
	PAM_Base
	Password string
}
/* and the result value consists of: */
type PAM_Authentication struct {
	AuthenticationResult int32
	UserName             string
	AuthorizationResult  int32
	AuthorizationError   string
}
/* If the username is empty in this request an attempt is made to
   authenticate as the administrator (set using rootpwmoddn).
   Some authorisation checks are already done during authentication so the
   response also includes authorisation information. */
const NSLCD_ACTION_PAM_AUTHENTICATION int32 = 0x000d0001

/* PAM authorisation check request. The result value consists of: */
type PAM_Authorization struct {
	Result int32
	Error  string
}
/* The authentication check may have already returned some authorisation
   information. The authorisation error message, if supplied, will be used
   by the PAM module instead of a message that is generated by the PAM
   module itself. */
const NSLCD_ACTION_PAM_AUTHORIZATION int32 = 0x000d0002; type Request_PAM_Authorization PAM_Base

/* PAM session open request. The result value consists of: */
type PAM_SessionOpen struct {
	SessionID string
}
/* This session id may be used to close this session with. */
const NSLCD_ACTION_PAM_SESSIONOPEN   int32 = 0x000d0003; type Request_PAM_SessionOpen PAM_Base

/* PAM session close request. This request has the following
   extra request value: */
type Request_PAM_SessionClose struct {
	PAM_Base
	SessionID string
}
/* and this calls only returns an empty response value. */
type PAM_SessionClose struct {}
const NSLCD_ACTION_PAM_SESSIONCLOSE  int32 = 0x000d0004

/* PAM password modification request. This requests has the following extra
   request values: */
type Request_PAM_PwMod struct {
	PAM_Base
	AsRoot      int32 /* 0=oldpasswd is user passwd, 1=oldpasswd is root passwd */
	OldPassword string
	NewPassword string
}
/* and returns the result values: */
type PAM_PwMod struct {
	Result int32
	Error  string
}
const NSLCD_ACTION_PAM_PWMOD         int32 = 0x000d0005

/* User information change request. This request allows one to change
   their full name and other information. The request parameters for this
   request are:
     STRING  user name
     INT32   asroot: 0=passwd is user passwd, 1=passwd is root passwd
     STRING  password
   followed by one or more of the below, terminated by NSLCD_USERMOD_END
     INT32   NSLCD_USERMOD_*
     STRING  new value
   the response consists of one or more of the entries below, terminated
   by NSLCD_USERMOD_END:
     INT32   NSLCD_USERMOD_*
     STRING  response
   (if the response is blank, the change went OK, otherwise the string
   contains an error message)
   */
type UserMod_Item struct {
	Key   int32
	Value string
}
type UserMod_ItemList []UserMod_Item
func (data UserMod_ItemList) nslcdWrite(fd io.Writer) {
	for _, item := range data {
		Write(fd, item)
	}
	Write(fd, NSLCD_USERMOD_END)
}
func (data *UserMod_ItemList) nslcdRead(fd io.Reader) {
	*data = make([]UserMod_Item, 0)
	for {
		var t int32
		Read(fd, &t)
		if t == NSLCD_USERMOD_END {
			return
		}
		var v UserMod_Item
		Read(fd, &v)
		*data = append(*data, v)
	}
}
var _ nslcdObject = UserMod_ItemList{}
var _ nslcdObjectPtr = &UserMod_ItemList{}
type Request_UserMod struct {
	UserName string
	AsRoot   int32
	Password string
	Items    UserMod_ItemList
}
type UserMod struct {
	Items []UserMod_Item
}
const NSLCD_ACTION_USERMOD           int32 = 0x000e0001

/* These are the possible values for the NSLCD_ACTION_USERMOD operation
   above. */
const (
	NSLCD_USERMOD_END        int32 = 0 /* end of change values */
	NSLCD_USERMOD_RESULT     int32 = 1 /* global result value */
	NSLCD_USERMOD_FULLNAME   int32 = 2 /* full name */
	NSLCD_USERMOD_ROOMNUMBER int32 = 3 /* room number */
	NSLCD_USERMOD_WORKPHONE  int32 = 4 /* office phone number */
	NSLCD_USERMOD_HOMEPHONE  int32 = 5 /* home phone number */
	NSLCD_USERMOD_OTHER      int32 = 6 /* other info */
	NSLCD_USERMOD_HOMEDIR    int32 = 7 /* home directory */
	NSLCD_USERMOD_SHELL      int32 = 8 /* login shell */
)

/* Request result codes. */
const (
	NSLCD_RESULT_BEGIN int32 = 1
	NSLCD_RESULT_END   int32 = 2
)

/* Partial list of PAM result codes. */
const (
	NSLCD_PAM_SUCCESS               int32 = 0  /* everything ok */
	NSLCD_PAM_PERM_DENIED           int32 = 6  /* Permission denied */
	NSLCD_PAM_AUTH_ERR              int32 = 7  /* Authc failure */
	NSLCD_PAM_CRED_INSUFFICIENT     int32 = 8  /* Cannot access authc data */
	NSLCD_PAM_AUTHINFO_UNAVAIL      int32 = 9  /* Cannot retrieve authc info */
	NSLCD_PAM_USER_UNKNOWN          int32 = 10 /* User not known */
	NSLCD_PAM_MAXTRIES              int32 = 11 /* Retry limit reached */
	NSLCD_PAM_NEW_AUTHTOK_REQD      int32 = 12 /* Password expired */
	NSLCD_PAM_ACCT_EXPIRED          int32 = 13 /* Account expired */
	NSLCD_PAM_SESSION_ERR           int32 = 14 /* Cannot make/remove session record */
	NSLCD_PAM_AUTHTOK_ERR           int32 = 20 /* Authentication token manipulation error */
	NSLCD_PAM_AUTHTOK_DISABLE_AGING int32 = 23 /* Password aging disabled */
	NSLCD_PAM_IGNORE                int32 = 25 /* Ignore module */
	NSLCD_PAM_ABORT                 int32 = 26 /* Fatal error */
	NSLCD_PAM_AUTHTOK_EXPIRED       int32 = 27 /* authentication token has expired */
)