/src/samba/lib/util/server_id.c
Line | Count | Source |
1 | | /* |
2 | | Unix SMB/CIFS implementation. |
3 | | Samba utility functions |
4 | | Copyright (C) Andrew Bartlett 2011 |
5 | | |
6 | | This program is free software; you can redistribute it and/or modify |
7 | | it under the terms of the GNU General Public License as published by |
8 | | the Free Software Foundation; either version 3 of the License, or |
9 | | (at your option) any later version. |
10 | | |
11 | | This program is distributed in the hope that it will be useful, |
12 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | GNU General Public License for more details. |
15 | | |
16 | | You should have received a copy of the GNU General Public License |
17 | | along with this program. If not, see <http://www.gnu.org/licenses/>. |
18 | | */ |
19 | | |
20 | | #include "replace.h" |
21 | | #include "lib/util/debug.h" |
22 | | #include "lib/util/fault.h" |
23 | | #include "lib/util/server_id.h" |
24 | | #include "lib/util/byteorder.h" |
25 | | #include "librpc/gen_ndr/server_id.h" |
26 | | |
27 | | bool server_id_same_process(const struct server_id *p1, |
28 | | const struct server_id *p2) |
29 | 0 | { |
30 | 0 | return ((p1->pid == p2->pid) && (p1->vnn == p2->vnn)); |
31 | 0 | } |
32 | | |
33 | | int server_id_cmp(const struct server_id *p1, const struct server_id *p2) |
34 | 0 | { |
35 | 0 | if (p1->vnn != p2->vnn) { |
36 | 0 | return (p1->vnn < p2->vnn) ? -1 : 1; |
37 | 0 | } |
38 | 0 | if (p1->pid != p2->pid) { |
39 | 0 | return (p1->pid < p2->pid) ? -1 : 1; |
40 | 0 | } |
41 | 0 | if (p1->task_id != p2->task_id) { |
42 | 0 | return (p1->task_id < p2->task_id) ? -1 : 1; |
43 | 0 | } |
44 | 0 | if (p1->unique_id != p2->unique_id) { |
45 | 0 | return (p1->unique_id < p2->unique_id) ? -1 : 1; |
46 | 0 | } |
47 | 0 | return 0; |
48 | 0 | } |
49 | | |
50 | | bool server_id_equal(const struct server_id *p1, const struct server_id *p2) |
51 | 0 | { |
52 | 0 | int cmp = server_id_cmp(p1, p2); |
53 | 0 | return (cmp == 0); |
54 | 0 | } |
55 | | |
56 | | char *server_id_str_buf(struct server_id id, struct server_id_buf *dst) |
57 | 0 | { |
58 | 0 | return server_id_str_buf_unique_ex(id, '\0', dst); |
59 | 0 | } |
60 | | |
61 | | char *server_id_str_buf_unique_ex(struct server_id id, |
62 | | char unique_delimiter, |
63 | | struct server_id_buf *dst) |
64 | 0 | { |
65 | 0 | if (id.unique_id == SERVERID_UNIQUE_ID_NOT_TO_VERIFY) { |
66 | 0 | unique_delimiter = '\0'; |
67 | 0 | } |
68 | |
|
69 | 0 | if (server_id_is_disconnected(&id)) { |
70 | 0 | strlcpy(dst->buf, "disconnected", sizeof(dst->buf)); |
71 | 0 | } else if ((id.vnn == NONCLUSTER_VNN) && (id.task_id == 0)) { |
72 | 0 | snprintf(dst->buf, sizeof(dst->buf), |
73 | 0 | "%"PRIu64"%c%"PRIu64"", |
74 | 0 | id.pid, unique_delimiter, id.unique_id); |
75 | 0 | } else if (id.vnn == NONCLUSTER_VNN) { |
76 | 0 | snprintf(dst->buf, sizeof(dst->buf), |
77 | 0 | "%"PRIu64".%"PRIu32"%c%"PRIu64"", |
78 | 0 | id.pid, id.task_id, |
79 | 0 | unique_delimiter, id.unique_id); |
80 | 0 | } else if (id.task_id == 0) { |
81 | 0 | snprintf(dst->buf, sizeof(dst->buf), |
82 | 0 | "%"PRIu32":%"PRIu64"%c%"PRIu64"", |
83 | 0 | id.vnn, id.pid, |
84 | 0 | unique_delimiter, id.unique_id); |
85 | 0 | } else { |
86 | 0 | snprintf(dst->buf, sizeof(dst->buf), |
87 | 0 | "%"PRIu32":%"PRIu64".%"PRIu32"%c%"PRIu64"", |
88 | 0 | id.vnn, id.pid, id.task_id, |
89 | 0 | unique_delimiter, id.unique_id); |
90 | 0 | } |
91 | 0 | return dst->buf; |
92 | 0 | } |
93 | | |
94 | | char *server_id_str_buf_unique(struct server_id id, struct server_id_buf *dst) |
95 | 0 | { |
96 | 0 | return server_id_str_buf_unique_ex(id, '/', dst); |
97 | 0 | } |
98 | | |
99 | | struct server_id server_id_from_string(uint32_t local_vnn, |
100 | | const char *pid_string) |
101 | 0 | { |
102 | 0 | return server_id_from_string_ex(local_vnn, '/', pid_string); |
103 | 0 | } |
104 | | |
105 | | struct server_id server_id_from_string_ex(uint32_t local_vnn, |
106 | | char unique_delimiter, |
107 | | const char *pid_string) |
108 | 0 | { |
109 | 0 | struct server_id templ = { |
110 | 0 | .vnn = NONCLUSTER_VNN, .pid = UINT64_MAX |
111 | 0 | }; |
112 | 0 | struct server_id result; |
113 | 0 | char unique_delimiter_found = '\0'; |
114 | 0 | int ret; |
115 | | |
116 | | /* |
117 | | * We accept various forms with 1, 2 or 3 component forms |
118 | | * because the server_id_str_buf() can print different forms, and |
119 | | * we want backwards compatibility for scripts that may call |
120 | | * smbclient. |
121 | | */ |
122 | |
|
123 | 0 | result = templ; |
124 | 0 | ret = sscanf(pid_string, "%"SCNu32":%"SCNu64".%"SCNu32"%c%"SCNu64, |
125 | 0 | &result.vnn, &result.pid, &result.task_id, |
126 | 0 | &unique_delimiter_found, &result.unique_id); |
127 | 0 | if (ret == 5 && unique_delimiter_found == unique_delimiter) { |
128 | 0 | return result; |
129 | 0 | } |
130 | | |
131 | 0 | result = templ; |
132 | 0 | ret = sscanf(pid_string, "%"SCNu32":%"SCNu64".%"SCNu32, |
133 | 0 | &result.vnn, &result.pid, &result.task_id); |
134 | 0 | if (ret == 3) { |
135 | 0 | return result; |
136 | 0 | } |
137 | | |
138 | 0 | result = templ; |
139 | 0 | ret = sscanf(pid_string, "%"SCNu32":%"SCNu64"%c%"SCNu64, |
140 | 0 | &result.vnn, &result.pid, |
141 | 0 | &unique_delimiter_found, &result.unique_id); |
142 | 0 | if (ret == 4 && unique_delimiter_found == unique_delimiter) { |
143 | 0 | return result; |
144 | 0 | } |
145 | | |
146 | 0 | result = templ; |
147 | 0 | ret = sscanf(pid_string, "%"SCNu32":%"SCNu64, |
148 | 0 | &result.vnn, &result.pid); |
149 | 0 | if (ret == 2) { |
150 | 0 | return result; |
151 | 0 | } |
152 | | |
153 | 0 | result = templ; |
154 | 0 | ret = sscanf(pid_string, "%"SCNu64".%"SCNu32"%c%"SCNu64, |
155 | 0 | &result.pid, &result.task_id, |
156 | 0 | &unique_delimiter_found, &result.unique_id); |
157 | 0 | if (ret == 4 && unique_delimiter_found == unique_delimiter) { |
158 | 0 | result.vnn = local_vnn; |
159 | 0 | return result; |
160 | 0 | } |
161 | | |
162 | 0 | result = templ; |
163 | 0 | ret = sscanf(pid_string, "%"SCNu64".%"SCNu32, |
164 | 0 | &result.pid, &result.task_id); |
165 | 0 | if (ret == 2) { |
166 | 0 | result.vnn = local_vnn; |
167 | 0 | return result; |
168 | 0 | } |
169 | | |
170 | 0 | result = templ; |
171 | 0 | ret = sscanf(pid_string, "%"SCNu64"%c%"SCNu64, |
172 | 0 | &result.pid, &unique_delimiter_found, &result.unique_id); |
173 | 0 | if (ret == 3 && unique_delimiter_found == unique_delimiter) { |
174 | 0 | result.vnn = local_vnn; |
175 | 0 | return result; |
176 | 0 | } |
177 | | |
178 | 0 | result = templ; |
179 | 0 | ret = sscanf(pid_string, "%"SCNu64, &result.pid); |
180 | 0 | if (ret == 1) { |
181 | 0 | result.vnn = local_vnn; |
182 | 0 | return result; |
183 | 0 | } |
184 | | |
185 | 0 | if (strcmp(pid_string, "disconnected") == 0) { |
186 | 0 | server_id_set_disconnected(&result); |
187 | 0 | return result; |
188 | 0 | } |
189 | | |
190 | 0 | return templ; |
191 | 0 | } |
192 | | |
193 | | /** |
194 | | * Set the serverid to the special value that represents a disconnected |
195 | | * client for (e.g.) durable handles. |
196 | | */ |
197 | | void server_id_set_disconnected(struct server_id *id) |
198 | 0 | { |
199 | 0 | *id = (struct server_id) { |
200 | 0 | .pid = UINT64_MAX, |
201 | 0 | .task_id = UINT32_MAX, |
202 | 0 | .vnn = NONCLUSTER_VNN, |
203 | 0 | .unique_id = SERVERID_UNIQUE_ID_NOT_TO_VERIFY, |
204 | 0 | }; |
205 | 0 | } |
206 | | |
207 | | /** |
208 | | * check whether a serverid is the special placeholder for |
209 | | * a disconnected client |
210 | | */ |
211 | | bool server_id_is_disconnected(const struct server_id *id) |
212 | 0 | { |
213 | 0 | struct server_id dis; |
214 | |
|
215 | 0 | SMB_ASSERT(id != NULL); |
216 | | |
217 | 0 | server_id_set_disconnected(&dis); |
218 | |
|
219 | 0 | return server_id_equal(id, &dis); |
220 | 0 | } |
221 | | |
222 | | void server_id_put(uint8_t buf[SERVER_ID_BUF_LENGTH], |
223 | | const struct server_id id) |
224 | 0 | { |
225 | 0 | SBVAL(buf, 0, id.pid); |
226 | 0 | SIVAL(buf, 8, id.task_id); |
227 | 0 | SIVAL(buf, 12, id.vnn); |
228 | 0 | SBVAL(buf, 16, id.unique_id); |
229 | 0 | } |
230 | | |
231 | | void server_id_get(struct server_id *id, |
232 | | const uint8_t buf[SERVER_ID_BUF_LENGTH]) |
233 | 0 | { |
234 | 0 | id->pid = BVAL(buf, 0); |
235 | 0 | id->task_id = IVAL(buf, 8); |
236 | 0 | id->vnn = IVAL(buf, 12); |
237 | 0 | id->unique_id = BVAL(buf, 16); |
238 | 0 | } |